import { WalletInterface, Transaction, WalletProtocol, Base64String, PubKeyHex, CreateActionArgs, TelemetryConfig } from '@bsv/sdk'; /** Line item type for spending authorization requests. */ export type LineItemType = 'input' | 'output' | 'fee'; /** Security level for DPACP protocol permissions. */ export type SecurityLevel = 0 | 1 | 2; /** The action a `signAction` hook call signs. */ export interface PermissionsModuleAction { reference: string; /** The signable transaction as `createAction` returned it. */ transaction: Transaction; /** True when the signed transaction is not broadcast. */ noSend: boolean; /** The `createAction` arguments as the permission modules returned them, before metadata encryption. */ createArgs?: CreateActionArgs; } /** A wallet request routed to a BRC-98/99/111 permission module. */ export interface PermissionsModuleRequest { method: string; args: object; originator: string; /** Set only for `signAction` hook calls. */ action?: PermissionsModuleAction; } /** * Invokes the underlying BRC-100 method with module-transformed arguments. * A semantic module can omit this call and return its own conforming result. */ export type PermissionsModuleNext = (args: object) => Promise; /** * Appends the BRC-205 capability attributes of `modules` to a wallet version string: * `base; key=value; key2=value2;`, one space after every nonterminal semicolon, no spaces around * `=`, a trailing semicolon when attributes are present. Modules are visited by scheme id and * their keys in order, so the result is deterministic. Attributes the underlying string already * carries are kept and their keys are not repeated; an invalid key or value, or one that would * exceed BRC-205's limits, is left out. With nothing to add the string is returned unchanged. */ export declare function withBrc205Capabilities(version: string, modules: Readonly>): string; export interface PermissionsModule { /** * BRC-205 capability attributes the module advertises through `getVersion`, as attribute key to * value. A key is a lowercase `brc-` (`[a-z][a-z0-9-]*`, 1-64 bytes); a value is * 1-256 bytes of unreserved or percent-encoded characters. Invalid entries are left out. */ capabilities?: Readonly>; /** * Optionally owns the complete execution of a P-module request. * * This is the semantic-extension hook for schemes whose behavior cannot be * expressed by argument and response transformation alone. The handler may * call `next` once to invoke the underlying BRC-100 method, or return a result * directly. When present, `onRequest` and `onResponse` are not invoked for the * delegated request. */ handleRequest?: (req: PermissionsModuleRequest, next: PermissionsModuleNext) => Promise; /** * Transforms the request before it's passed to the underlying wallet. * Can check and enforce permissions, throw errors, or modify any arguments as needed prior to invocation. * * @param req - The incoming request with method, args, and originator * @returns Transformed arguments that will be passed to the underlying wallet */ onRequest: (req: PermissionsModuleRequest) => Promise<{ args: object; }>; /** * Transforms the response from the underlying wallet before returning to caller. * * @param res - The response from the underlying wallet * @param context - Metadata about the original request (method, originator, and for `signAction` the action) * @returns Transformed response to return to the caller */ onResponse: (res: any, context: { method: string; originator: string; action?: PermissionsModuleAction; }) => Promise; } /** * Describes a group of permissions that can be requested together. * This structure is based on BRC-73. */ export interface GroupedPermissions { description?: string; spendingAuthorization?: { amount: number; description: string; }; protocolPermissions?: Array<{ protocolID: WalletProtocol; counterparty?: string; description: string; }>; basketAccess?: Array<{ basket: string; description: string; }>; certificateAccess?: Array<{ type: string; fields: string[]; verifierPublicKey: string; description: string; }>; } /** * The object passed to the UI when a grouped permission is requested. */ export interface GroupedPermissionRequest { originator: string; requestID: string; permissions: GroupedPermissions; } /** * Signature for functions that handle a grouped permission request event. */ export type GroupedPermissionEventHandler = (request: GroupedPermissionRequest) => void | Promise; export interface CounterpartyPermissions { description?: string; protocols: Array<{ protocolName: string; protocolID?: WalletProtocol; description?: string; }>; } export interface CounterpartyPermissionRequest { originator: string; requestID: string; counterparty: PubKeyHex; counterpartyLabel?: string; permissions: CounterpartyPermissions; } export type CounterpartyPermissionEventHandler = (request: CounterpartyPermissionRequest) => void | Promise; /** * Describes a single requested permission that the user must either grant or deny. * * Four categories of permission are supported, each with a unique protocol: * 1) protocol - "DPACP" (Domain Protocol Access Control Protocol) * 2) basket - "DBAP" (Domain Basket Access Protocol) * 3) certificate - "DCAP" (Domain Certificate Access Protocol) * 4) spending - "DSAP" (Domain Spending Authorization Protocol) * * This model underpins "requests" made to the user for permission, which the user can * either grant or deny. The manager can then create on-chain tokens (PushDrop outputs) * if permission is granted. Denying requests cause the underlying operation to throw, * and no token is created. An "ephemeral" grant is also possible, denoting a one-time * authorization without an associated persistent on-chain token. */ export interface PermissionRequest { type: 'protocol' | 'basket' | 'certificate' | 'spending'; originator: string; displayOriginator?: string; usageType?: string; privileged?: boolean; protocolID?: WalletProtocol; counterparty?: string; basket?: string; certificate?: { verifier: string; certType: string; fields: string[]; }; spending?: { satoshis: number; lineItems?: Array<{ type: LineItemType; description: string; satoshis: number; }>; }; reason?: string; renewal?: boolean; previousToken?: PermissionToken; } /** * Signature for functions that handle a permission request event, e.g. "Please ask the user to allow basket X". */ export type PermissionEventHandler = (request: PermissionRequest & { requestID: string; }) => void | Promise; /** * Data structure representing an on-chain permission token. * It is typically stored as a single unspent PushDrop output in a special "internal" admin basket belonging to * the user, held in their underlying wallet. * * It can represent any of the four permission categories by having the relevant fields: * - DPACP: originator, privileged, protocol, securityLevel, counterparty * - DBAP: originator, basketName * - DCAP: originator, privileged, verifier, certType, certFields * - DSAP: originator, authorizedAmount */ export interface PermissionToken { /** The transaction ID where this token resides. */ txid: string; /** The current transaction encapsulating the token. */ tx: number[]; /** The output index within that transaction. */ outputIndex: number; /** The exact script hex for the locking script. */ outputScript: string; /** The amount of satoshis assigned to the permission output (often 1). */ satoshis: number; /** The originator domain or FQDN that is allowed to use this permission. */ originator: string; /** * The raw, unnormalized originator string captured at the time the permission * token was created. This is preserved so we can continue to recognize legacy * permissions that were stored with different casing or explicit default ports. */ rawOriginator?: string; /** The expiration time for this token in UNIX epoch seconds. (0 or omitted for spending authorizations, which are indefinite) */ expiry: number; /** Whether this token grants privileged usage (for protocol or certificate). */ privileged?: boolean; /** The protocol name, if this is a DPACP token. */ protocol?: string; /** The security level (0,1,2) for DPACP. */ securityLevel?: SecurityLevel; /** The counterparty, for DPACP. */ counterparty?: string; /** The name of a basket, if this is a DBAP token. */ basketName?: string; /** The certificate type, if this is a DCAP token. */ certType?: string; /** The certificate fields that this token covers, if DCAP token. */ certFields?: string[]; /** The "verifier" public key string, if DCAP. */ verifier?: string; /** For DSAP, the maximum authorized spending for the month. */ authorizedAmount?: number; } /** * Encrypts metadata through `wallet` as a permissions manager with `encryptWalletMetadata` does. * Permission modules use this for metadata they store through the underlying wallet directly. */ export declare function encryptMetadata(wallet: WalletInterface, plaintext: string, originator?: string): Promise; /** * Decrypts metadata that a permissions manager with `encryptWalletMetadata` stored through `wallet`. * A value that does not decrypt, such as metadata stored without encryption, is returned unchanged. * Permission modules use this to read metadata from their own baskets through the underlying wallet. */ export declare function maybeDecryptMetadata(wallet: WalletInterface, ciphertext: Base64String, originator?: string): Promise; /** * The set of callbacks that external code can bind to, e.g. to display UI prompts or logs * when a permission is requested. */ export interface WalletPermissionsManagerCallbacks { onProtocolPermissionRequested?: PermissionEventHandler[]; onBasketAccessRequested?: PermissionEventHandler[]; onCertificateAccessRequested?: PermissionEventHandler[]; onSpendingAuthorizationRequested?: PermissionEventHandler[]; onGroupedPermissionRequested?: GroupedPermissionEventHandler[]; onCounterpartyPermissionRequested?: CounterpartyPermissionEventHandler[]; } /** * Configuration object for the WalletPermissionsManager. If a given option is `false`, * the manager will skip or alter certain permission checks or behaviors. * * By default, all of these are `true` unless specified otherwise. This is the most secure configuration. */ export interface PermissionsManagerConfig { /** * Optional provider-neutral permission timing. Originators, permission-token * contents, manifests, descriptions, labels, and transaction data are never * emitted by the generic instrumentation. */ telemetry?: TelemetryConfig; /** * A map of P-basket/protocol permission scheme modules. * * Keys are scheme IDs (e.g., "btms"), values are PermissionsModule instances. * * Each module handles basket/protocol names of the form: `p ` * * The WalletPermissionManager detects P-prefix baskets/protocols and delegates * request/response transformation to the corresponding module. * * If no module exists for a given schemeID, the wallet will reject access. */ permissionModules?: Record; /** * For `createSignature` and `verifySignature`, * require a "protocol usage" permission check? */ seekProtocolPermissionsForSigning?: boolean; /** * For methods that perform encryption (encrypt/decrypt), require * a "protocol usage" permission check? */ seekProtocolPermissionsForEncrypting?: boolean; /** * For methods that perform HMAC creation or verification (createHmac, verifyHmac), * require a "protocol usage" permission check? */ seekProtocolPermissionsForHMAC?: boolean; /** * For revealing counterparty-level or specific key linkage revelation information, * should we require permission? */ seekPermissionsForKeyLinkageRevelation?: boolean; /** * For revealing any user public key (getPublicKey) **other** than the identity key, * should we require permission? */ seekPermissionsForPublicKeyRevelation?: boolean; /** * If getPublicKey is requested with `identityKey=true`, do we require permission? */ seekPermissionsForIdentityKeyRevelation?: boolean; /** * If discoverByIdentityKey / discoverByAttributes are called, do we require permission * for "identity resolution" usage? This covers both locally authoritative contact results and * third-party certificate-overlay results; permission does not change either source's trust * semantics. */ seekPermissionsForIdentityResolution?: boolean; /** * When we do internalizeAction with `basket insertion`, or include outputs in baskets * with `createAction, do we ask for basket permission? */ seekBasketInsertionPermissions?: boolean; /** * When relinquishOutput is called, do we ask for basket permission? */ seekBasketRemovalPermissions?: boolean; /** * When listOutputs is called, do we ask for basket permission? */ seekBasketListingPermissions?: boolean; /** * When createAction is called with labels, do we ask for "label usage" permission? */ seekPermissionWhenApplyingActionLabels?: boolean; /** * When listActions is called with labels, do we ask for "label usage" permission? */ seekPermissionWhenListingActionsByLabel?: boolean; /** * If proving a certificate (proveCertificate) or revealing certificate fields, * do we require a "certificate access" permission? */ seekCertificateDisclosurePermissions?: boolean; /** * If acquiring a certificate (acquireCertificate), do we require a permission check? */ seekCertificateAcquisitionPermissions?: boolean; /** * If relinquishing a certificate (relinquishCertificate), do we require a permission check? */ seekCertificateRelinquishmentPermissions?: boolean; /** * If listing a user's certificates (listCertificates), do we require a permission check? */ seekCertificateListingPermissions?: boolean; /** * Should transaction descriptions, input descriptions, and output descriptions be encrypted * when before they are passed to the underlying wallet, and transparently decrypted when retrieved? */ encryptWalletMetadata?: boolean; /** * If the originator tries to spend wallet funds (netSpent > 0 in createAction), * do we seek spending authorization? */ seekSpendingPermissions?: boolean; /** * If true, triggers a grouped permission request flow based on the originator's `manifest.json`. */ seekGroupedPermission?: boolean; /** * If false, permissions are checked without regard for whether we are in * privileged mode. Privileged status is ignored with respect to whether * permissions are granted. Internally, they are always sought and checked * with privileged=false, regardless of the actual value. */ differentiatePrivilegedOperations?: boolean; /** * An allowlist mapping counterparty identity public keys (hex) * to protocol names that are automatically permitted * without prompting the user. */ whitelistedCounterparties?: { [counterparty: PubKeyHex]: string[]; }; } export declare class WalletPermissionsManager implements WalletInterface { /** A reference to the BRC-100 wallet instance. */ private readonly underlying; /** The "admin" domain or FQDN that is implicitly allowed to do everything. */ private readonly adminOriginator; /** * Event callbacks that external code can subscribe to, e.g. to show a UI prompt * or log events. Each event can have multiple handlers. */ private readonly callbacks; /** * We queue parallel requests for the same resource so that only one * user prompt is created for a single resource. If multiple calls come * in at once for the same "protocol:domain:privileged:counterparty" etc., * they get merged. * * The key is a string derived from the operation; the value is an object with a reference to the * associated request and an array of pending promise resolve/reject pairs, one for each active * operation that's waiting on the particular resource described by the key. */ private readonly activeRequests; /** Cache recently confirmed permissions to avoid repeated lookups. */ private readonly permissionCache; private readonly recentGrants; /** Originator binding for partial actions issued through this manager. */ private readonly pendingActionOriginators; /** Exact authorized transaction template for each pending action. */ private readonly pendingActionTemplates; /** References that failed authorization and could not be conclusively aborted. */ private readonly blockedActionReferences; /** Pending references whose action was created with `noSend`. */ private readonly pendingNoSendReferences; /** P-modules that handled each pending action's createAction, in request order. */ private readonly pendingActionModules; /** The createAction arguments those P-modules returned, for their signAction hooks. */ private readonly pendingActionCreateArgs; /** * Originator binding for signed no-send actions, keyed by lowercase txid. * Signing drops the pending reference, so without this a non-admin caller * could not release the action it created. */ private readonly noSendActions; /** Reference a caller signed a no-send action under, to that action's txid key. */ private readonly noSendActionReferences; private permissionTokenLockingKeyPromise?; /** * Token mints currently being written on-chain, keyed by permission cache * key. A granted permission is only cached once its token finishes minting * (network seconds); ensures arriving in that window await the in-flight * mint instead of re-prompting the user for a permission they just granted. * Stored promises never reject. */ private readonly mintsInFlight; /** * Monotonic nonce used to keep spending prompts one-to-one with the wallet * operations they authorize. Unlike capability permissions, spending * requests must never share a pending approval merely because their amounts * happen to match. */ private spendingRequestSequence; private readonly manifestCache; private readonly manifestFetchInProgress; private static readonly MANIFEST_CACHE_TTL_MS; private static readonly MANIFEST_MAX_BYTES; private static readonly MANIFEST_TIMEOUT_MS; private readonly groupedPermissionFlowTail; private readonly pactEstablishedCache; /** * Parsed BEEF bundles keyed by the raw BEEF array of a `listOutputs` * result, so token scans parse each bundle once instead of once per output. * `null` records a bundle that failed to parse. WeakMap-keyed so entries * are released with their results. */ private readonly parsedBeefCache; /** Counts token-field decrypts so long scans can periodically yield. */ private tokenFieldDecryptCount; /** How long a cached permission remains valid (5 minutes). */ private static readonly CACHE_TTL_MS; /** Window during which freshly granted permissions are auto-allowed (except spending). */ private static readonly RECENT_GRANT_COVER_MS; /** * Configuration that determines whether to skip or apply various checks and encryption. */ private readonly config; private readonly telemetry; /** * Constructs a new Permissions Manager instance. * * @param underlyingWallet The underlying BRC-100 wallet, where requests are forwarded after permission is granted * @param adminOriginator The domain or FQDN that is automatically allowed everything * @param config A set of boolean flags controlling how strictly permissions are enforced */ constructor(underlyingWallet: WalletInterface, adminOriginator: string, config?: PermissionsManagerConfig); /** * Delegates a wallet method call to a P-module if the basket or protocol name uses a P-scheme. * Handles the full request/response transformation flow. * * @param basketOrProtocolName - The basket or protocol name to check for p-module delegation * @param method - The wallet method name being called * @param args - The original args passed to the method * @param originator - The originator of the request * @param underlyingCall - Callback that executes the underlying wallet method with transformed args * @returns The transformed response, or null if not a P-basket/protocol (caller should continue normal flow) */ private delegateToPModuleIfNeeded; /** * Adds a permission module for the given schemeID if needed, throwing if unsupported. */ private addPModuleByScheme; /** * Splits labels into P and non-P lists, registering any P-modules encountered. * * P-labels follow BRC-111 format: `p ` * - Must start with "p " (lowercase p + space) * - Module ID must be at least 1 character with no spaces * - Single space separates module ID from payload * - Payload must be at least 1 character * * @example Valid: "p btms token123", "p invoicing invoice 2026-02-02" * @example Invalid: "p btms" (no payload), "p btms " (empty payload), "p data" (empty moduleId) * * @param labels - Array of label strings to process * @param pModulesByScheme - Map to populate with discovered p-modules * @returns Array of non-P labels for normal permission checks * @throws Error if p-label format is invalid or module is unsupported */ private splitLabelsByPermissionModule; /** * Decrypts custom instructions in listOutputs results if encryption is configured. */ private decryptListOutputsMetadata; /** * Decrypts metadata in listActions results if encryption is configured. */ private decryptListActionsMetadata; private decryptSingleActionMetadata; private decryptActionOutputMetadata; /** * Binds a callback function to a named event, such as `onProtocolPermissionRequested`. * * @param eventName The name of the event to listen to * @param handler A function that handles the event * @returns A numeric ID you can use to unbind later */ bindCallback(eventName: keyof WalletPermissionsManagerCallbacks, handler: PermissionEventHandler | GroupedPermissionEventHandler | CounterpartyPermissionEventHandler): number; /** * Unbinds a previously registered callback by either its numeric ID (returned by `bindCallback`) * or by exact function reference. * * @param eventName The event name, e.g. "onProtocolPermissionRequested" * @param reference Either the numeric ID or the function reference * @returns True if successfully unbound, false otherwise */ unbindCallback(eventName: keyof WalletPermissionsManagerCallbacks, reference: number | Function): boolean; /** * Internally triggers a named event, calling all subscribed listeners. * Each callback is awaited in turn (though errors are swallowed so that * one failing callback doesn't prevent the others). * * @param eventName The event name * @param param The parameter object passed to all listeners */ private callEvent; private grantPersistentPermission; /** * Grants a previously requested permission. * This method: * 1) Resolves all pending promise calls waiting on this request * 2) Optionally creates or renews an on-chain PushDrop token (unless `ephemeral===true`) * * @param params requestID to identify which request is granted, plus optional expiry * or `ephemeral` usage, etc. */ grantPermission(params: { requestID: string; expiry?: number; ephemeral?: boolean; amount?: number; }): Promise; /** * Denies a previously requested permission. * This method rejects all pending promise calls waiting on that request * * @param requestID requestID identifying which request to deny */ denyPermission(requestID: string): Promise; /** * Grants a previously requested grouped permission. * @param params.requestID The ID of the request being granted. * @param params.granted A subset of the originally requested permissions that the user has granted. * @param params.expiry An optional expiry time (in seconds) for the new permission tokens. */ grantGroupedPermission(params: { requestID: string; granted: Partial; expiry?: number; }): Promise; /** * Denies a previously requested grouped permission. * @param requestID The ID of the request being denied. */ /** * Validates that every entry in `granted` was part of the original `requested` set. * Throws an error on the first mismatch. */ private validateGrantedPermissionsSubset; private denyActiveRequest; private settleActiveGrant; private persistPermissionGrant; denyGroupedPermission(requestID: string): Promise; dismissGroupedPermission(requestID: string): Promise; grantCounterpartyPermission(params: { requestID: string; granted: Partial; expiry?: number; }): Promise; denyCounterpartyPermission(requestID: string): Promise; /** * Ensures the originator has protocol usage permission. * If no valid (unexpired) permission token is found, triggers a permission request flow. */ ensureProtocolPermission({ originator, privileged, protocolID, counterparty, reason, seekPermission, usageType }: { originator: string; privileged: boolean; protocolID: WalletProtocol; counterparty: string; reason?: string; seekPermission?: boolean; usageType: 'signing' | 'encrypting' | 'hmac' | 'publicKey' | 'identityKey' | 'linkageRevelation' | 'generic'; }): Promise; /** * Ensures the originator has basket usage permission for the specified basket. * If not, triggers a permission request flow. */ ensureBasketAccess({ originator, basket, reason, seekPermission, usageType }: { originator: string; basket: string; reason?: string; seekPermission?: boolean; usageType: 'insertion' | 'removal' | 'listing'; }): Promise; /** Returns false when the basket usageType does NOT need a permission check (config-gated). */ private isBasketUsageRequired; /** * Ensures the originator has a valid certificate permission. * This is relevant when revealing certificate fields in DCAP contexts. */ ensureCertificateAccess({ originator, privileged, verifier, certType, fields, reason, seekPermission, usageType }: { originator: string; privileged: boolean; verifier: string; certType: string; fields: string[]; reason?: string; seekPermission?: boolean; usageType: 'disclosure'; }): Promise; /** * Ensures the originator has spending authorization (DSAP) for a certain satoshi amount. * If the existing token limit is insufficient, attempts to renew. If no token, attempts to create one. */ ensureSpendingAuthorization({ originator, satoshis, lineItems, reason, seekPermission }: { originator: string; satoshis: number; lineItems?: Array<{ type: LineItemType; description: string; satoshis: number; }>; reason?: string; seekPermission?: boolean; /** * @deprecated Retained for source compatibility. Spending grants are never * cached or reused, regardless of this value. */ allowRecentGrant?: boolean; }): Promise; /** * Ensures the originator has label usage permission. * If no valid (unexpired) permission token is found, triggers a permission request flow. */ ensureLabelAccess({ originator, label, reason, seekPermission, usageType }: { originator: string; label: string; reason?: string; seekPermission?: boolean; usageType: 'apply' | 'list'; }): Promise; /** * Returns true when the given usageType is configured to skip permission checks. */ private isProtocolUsageTypeExempted; private isProtocolInCounterpartyPermissions; private validateCounterpartyPermissions; private fetchManifestPermissions; private readBoundedManifest; private fetchManifestGroupPermissions; private filterAlreadyGrantedPermissions; private hasAnyPermissionsToRequest; private hasGroupedPermissionRequestedHandlers; private hasCounterpartyPermissionRequestedHandlers; private hasPactEstablished; private markPactEstablished; private maybeRequestPact; private joinOrCreatePactRequest; private maybeRequestPeerGroupedLevel2ProtocolPermissions; private withGroupedPermissionFlowLock; private checkSpecificPermissionAfterGroupFlow; private isRequestIncludedInGroupPermissions; private maybeRequestGroupedPermissions; /** * Joins an existing grouped permission request (piggybacks on the existing promise), or creates * a new one and fires the onGroupedPermissionRequested event. */ private joinOrCreateGroupedRequest; /** * A central method that triggers the permission request flow. * - It checks if there's already an active request for the same key * - If so, we wait on that existing request rather than creating a duplicative one * - Otherwise we create a new request queue, call the relevant "onXXXRequested" event, * and return a promise that resolves once permission is granted or rejects if denied. */ private requestPermissionFlow; private requestPermissionFlowCore; /** Returns true when an active-request queue already has pending waiters for this key. */ private isPiggybacking; /** Appends to an existing request queue and waits for resolution. */ private piggybackOnExistingQueue; /** Runs the grouped-permission flow (with or without a lock) and checks post-group satisfaction. */ private resolveGroupedFlow; /** Creates a new active-request queue entry, fires the event, and returns the promise. */ private enqueueAndFireEvent; /** Fires the appropriate onXXXRequested event based on the request type. */ private firePermissionRequestEvent; private callPermissionEvent; /** * We will use a administrative "permission token encryption" protocol to store fields * in each permission's PushDrop script. This ensures that only the user's wallet * can decrypt them. In practice, this data is not super sensitive, but we still * follow the principle of least exposure. */ private static readonly PERM_TOKEN_ENCRYPTION_PROTOCOL; /** We always use `keyID="1"` and `counterparty="self"` for these encryption ops. */ private encryptPermissionTokenField; /** * Extracts a transaction from a `listOutputs` result's BEEF bundle, parsing * the bundle only once per result. Calling * `Transaction.fromBEEF(result.BEEF, txid)` per output re-parses the entire * bundle every time — O(n²) in the number of outputs — which can block the * caller's thread (in browser wallets, the UI) for seconds on large * permission baskets. */ private transactionFromResultBeef; private permissionTokenLockingKey; private authenticatedPermissionTokenSource; private decryptPermissionTokenField; private decryptPermissionTokenText; /** * Encrypts wallet metadata if configured to do so, otherwise returns the original plaintext for storage. * @param plaintext The metadata to encrypt if configured to do so * @returns The encrypted metadata, or the original value if encryption was disabled. */ private maybeEncryptMetadata; /** * Attempts to decrypt metadata. if decryption fails, assumes the value is already plaintext and returns it. * @param ciphertext The metadata to attempt decryption for. * @returns The decrypted metadata. If decryption fails, returns the original value instead. */ private maybeDecryptMetadata; /** Helper to see if a token's expiry is in the past. */ private isTokenExpired; /** Decrypts the standard 6 fields from a protocol (DPACP) PushDrop script. */ private decryptProtocolTokenFields; private protocolTokenTags; private parseProtocolTokenOutput; private parseBasketTokenOutput; private parseCertificateTokenOutput; /** Parses outpoint string "txid.vout" into [txid, outputIndex]. */ private parseOutpoint; /** Looks for a DPACP permission token matching origin/domain, privileged, protocol, cpty. */ private findProtocolToken; /** Finds ALL DPACP permission tokens matching origin/domain, privileged, protocol, cpty. Never filters by expiry. */ private findAllProtocolTokens; /** Looks for a DBAP token matching (originator, basket). */ private findBasketToken; /** Looks for a DCAP token matching (origin, privileged, verifier, certType, fields subset). */ private findCertificateToken; /** Looks for a DSAP token matching origin, returning the first one found. */ private findSpendingToken; /** * Returns the current month and year in UTC as a string in the format "YYYY-MM". * * @returns {string} The current month and year in UTC. */ private getCurrentMonthYearUTC; /** * Returns spending for an originator in the current calendar month. */ querySpentSince(token: PermissionToken): Promise; /** * Creates a brand-new permission token as a single-output PushDrop script in the relevant admin basket. * * The main difference between each type of token is in the "fields" we store in the PushDrop script. * * @param r The permission request * @param expiry The expiry epoch time * @param amount For DSAP, the authorized spending limit */ private createPermissionOnChain; private mapWithConcurrency; private runBestEffortBatches; private runBestEffortChunk; private buildPermissionOutput; private createPermissionTokensBestEffort; private renewPermissionTokensBestEffort; private permissionTokenInputSigners; private completePermissionTokenAction; private coalescePermissionTokens; /** * Renews a permission token by spending the old token as input and creating a new token output. * This invalidates the old token and replaces it with a new one. * * @param oldToken The old token to consume * @param r The permission request being renewed * @param newExpiry The new expiry epoch time * @param newAmount For DSAP, the new authorized amount */ private renewPermissionOnChain; /** * Builds the encrypted array of fields for a PushDrop permission token * (protocol / basket / certificate / spending). */ private buildPushdropFields; /** * Helper to build an array of tags for the new output, matching the user request's * origin, basket, privileged, protocol name, etc. */ private buildTagsForRequest; /** * Lists all protocol permission tokens (DPACP) with optional filters. * @param originator Optional originator domain to filter by * @param privileged Optional boolean to filter by privileged status * @param protocolName Optional protocol name to filter by * @param protocolSecurityLevel Optional protocol security level to filter by * @param counterparty Optional counterparty to filter by * @returns Array of permission tokens that match the filter criteria */ listProtocolPermissions({ originator, privileged, protocolName, protocolSecurityLevel, counterparty }?: { originator?: string; privileged?: boolean; protocolName?: string; protocolSecurityLevel?: number; counterparty?: string; }): Promise; /** Builds the base tag array for protocol permission listing. */ private buildProtocolFilterTags; /** Decodes and appends protocol permission tokens from a listOutputs result. */ private collectProtocolTokens; /** * Returns true if the originator already holds a valid unexpired protocol permission. * This calls `ensureProtocolPermission` with `seekPermission=false`, so it won't prompt. */ hasProtocolPermission(params: { originator: string; privileged: boolean; protocolID: WalletProtocol; counterparty: string; }): Promise; /** * Lists basket permission tokens (DBAP) for a given originator or basket (or for all if not specified). * @param params.originator Optional originator to filter by * @param params.basket Optional basket name to filter by * @returns Array of permission tokens that match the filter criteria */ listBasketAccess(params?: { originator?: string; basket?: string; }): Promise; /** Decodes and appends basket permission tokens from a listOutputs result. */ private collectBasketTokens; /** * Returns `true` if the originator already holds a valid unexpired basket permission for `basket`. */ hasBasketAccess(params: { originator: string; basket: string; }): Promise; /** * Lists spending authorization tokens (DSAP) for a given originator (or all). */ listSpendingAuthorizations(params: { originator?: string; }): Promise; /** * Returns `true` if the originator already holds a valid spending authorization token * with enough available monthly spend. We do not prompt (seekPermission=false). */ hasSpendingAuthorization(params: { originator: string; satoshis: number; }): Promise; /** * Lists certificate permission tokens (DCAP) with optional filters. * @param originator Optional originator domain to filter by * @param privileged Optional boolean to filter by privileged status * @param certType Optional certificate type to filter by * @param verifier Optional verifier to filter by * @returns Array of permission tokens that match the filter criteria */ listCertificateAccess(params?: { originator?: string; privileged?: boolean; certType?: Base64String; verifier?: PubKeyHex; }): Promise; /** Decodes and appends certificate permission tokens from a listOutputs result. */ private collectCertificateTokens; /** * Returns `true` if the originator already holds a valid unexpired certificate access * for the given certType/fields. Does not prompt the user. */ hasCertificateAccess(params: { originator: string; privileged: boolean; verifier: string; certType: string; fields: string[]; }): Promise; revokePermissions(oldTokens: PermissionToken[]): Promise; revokeAllForOriginator(originator: string, opts?: { protocol?: boolean; basket?: boolean; certificate?: boolean; spending?: boolean; }): Promise; private revokePermissionTokensBestEffort; private revokePermissionTokensChunk; /** * Revokes a permission token by spending it with no replacement output. * The manager builds a BRC-100 transaction that consumes the token, effectively invalidating it. */ revokePermission(oldToken: PermissionToken): Promise; createAction(args: Parameters[0], originator?: string): ReturnType; /** Scans outputs to split P-scheme baskets from regular baskets; registers P-modules as a side effect. */ private collectNonPBaskets; /** Enforces signAndProcess=false for non-admin originators; throws if admin override is missing. */ private enforceSignAndProcess; /** Encrypts all description/instruction fields in args in-place; returns original (plaintext) copies. */ private encryptActionMetadata; /** Encrypts P-basket output custom instructions as the permission modules left them. */ private encryptCreateActionModuleMetadata; /** Calls underlying createAction, chaining P-module request/response transforms when needed. */ private callCreateActionWithPModules; /** * Computes the net satoshis the originator is spending in a createAction call, * accounting for foreign (originator-provided) inputs and outputs plus the fee. * Also builds the line items list for the spending authorization request. */ /** * Defense-in-depth verification that each caller-requested output (locking * script + amount) is present in the transaction returned for signing. * * The scripts in the signable transaction originate from storage. A malicious * or compromised remote storage provider could substitute a different * recipient script for a caller-specified output. The signer * (buildSignableTransaction) rejects this at the source; this is an * independent check at the permissions layer so the substitution is caught * regardless of how the signable transaction was produced. * * Outputs are matched as a multiset on (lockingScript, satoshis): the * transaction also contains change/commission outputs and the output order is * randomized by default, and a caller may legitimately request the same * script+amount more than once. * * A sendMax output is requested with the `maxPossibleSatoshis` sentinel * (see storage/methods/generateChange); storage's funding step rewrites it * to the actual funded amount before returning the signable transaction, so * it can never be matched by amount. Fixed-amount outputs are matched first, * as an exact (script, satoshis) multiset exactly as before; any * sentinel-valued requested output is then matched by locking script alone * against whatever the fixed-amount pass left unused. Matching the sentinel * only after fixed-amount outputs are claimed keeps a fixed output that * happens to share the sentinel's locking script from being mis-paired with * it. `generateChange` permits at most one `maxPossibleSatoshis` output per * call; more than one sentinel-valued request is simply matched * independently, first-fit, in requested order. * * @returns the resolved actual satoshis for each requested output index * (identical to the request for a fixed-amount output; the real funded * amount for a sendMax sentinel), so callers can bill the real amount * instead of the sentinel. * @throws Error if any caller-requested output is absent from the transaction. */ private verifyRequestedOutputsPresent; private computeNetSpend; private checkedSatoshiTotal; private inputOutpointForBinding; /** Binds a wallet's final result to the exact template that passed authorization. */ private assertAuthorizedSignResult; private blockAndAbortAction; private assertPendingActionOriginator; private bindPendingAction; private clearPendingAction; /** Lets the originator that created a signed no-send action, and only it, abort it. */ private recordNoSendAction; private forgetNoSendAction; /** Positive broadcast/queue results retire ownership; failures remain retryable. */ private forgetSentNoSendActions; private forgetSentNoSendActionsInError; /** The action a signAction hook call signs, from the template bound at createAction. */ private signingAction; /** Passes signAction args through the P-modules that handled the action's createAction, in request order. */ private signActionArgsThroughPModules; /** Passes a signAction result back through the same P-modules in reverse order. */ private signActionResultThroughPModules; signAction(...args: Parameters): ReturnType; abortAction(...args: Parameters): ReturnType; listActions(...args: Parameters): ReturnType; private collectInternalizeActionBaskets; private authorizeInternalizeActionBaskets; private authorizeInternalizeActionLabels; /** * Encrypts custom instructions that permission modules can still introduce. * Normal-basket instructions are already encrypted once by * authorizeInternalizeActionBaskets, before modules run. Encrypting them * again here wrapped ciphertext inside ciphertext whenever a registered * p-label or p-basket caused modules to run, and listOutputs decrypts only * one layer. Permission-module baskets are not covered by that earlier pass. */ private encryptInternalizeActionModuleMetadata; private runInternalizeActionModules; internalizeAction(...args: Parameters): ReturnType; listOutputs(...args: Parameters): ReturnType; relinquishOutput(...args: Parameters): ReturnType; getPublicKey(...args: Parameters): ReturnType; revealCounterpartyKeyLinkage(...args: Parameters): ReturnType; revealSpecificKeyLinkage(...args: Parameters): ReturnType; encrypt(...args: Parameters): ReturnType; decrypt(...args: Parameters): ReturnType; createHmac(...args: Parameters): ReturnType; verifyHmac(...args: Parameters): ReturnType; createSignature(...args: Parameters): ReturnType; verifySignature(...args: Parameters): ReturnType; acquireCertificate(...args: Parameters): ReturnType; listCertificates(...args: Parameters): ReturnType; proveCertificate(...args: Parameters): ReturnType; relinquishCertificate(...args: Parameters): ReturnType; discoverByIdentityKey(...args: Parameters): ReturnType; discoverByAttributes(...args: Parameters): ReturnType; isAuthenticated(...args: Parameters): ReturnType; waitForAuthentication(...args: Parameters): ReturnType; getHeight(...args: Parameters): ReturnType; getHeaderForHeight(...args: Parameters): ReturnType; getNetwork(...args: Parameters): ReturnType; /** * The underlying wallet's version string with the BRC-205 capability attributes of every * configured permission module appended (see `withBrc205Capabilities`). */ getVersion(...args: Parameters): ReturnType; /** Returns true if the specified origin is the admin originator. */ private isAdminOriginator; /** * Checks if the given protocol is admin-reserved per BRC-100 rules: * * - Must not start with `admin` (admin-reserved) * - Must not start with `p ` (allows for future specially permissioned protocols) * * If it violates these rules and the caller is not admin, we consider it "admin-only." */ private isAdminProtocol; /** * Checks if the given label is admin-reserved per BRC-100 rules: * * - Must not start with `admin` (admin-reserved) * - Must not start with `p ` (permissioned labels requiring a permission module) * * If it violates these rules and the caller is not admin, we consider it "admin-only." */ private isAdminLabel; /** * Checks if the given basket is admin-reserved per BRC-100 rules: * * - Must not start with `admin` * - Must not be `default` (some wallets use this for internal operations) * - Must not start with `p ` (future specially permissioned baskets) */ private isAdminBasket; /** * Whether the permission is satisfied without consulting on-chain tokens: * cached, recently granted, or — when the user just granted it and its * token is still minting — after the in-flight mint settles. Spares the * user a duplicate prompt for a grant they already made moments ago. */ private hasRecentOrPendingGrant; private hasRecentOrPendingGrantCore; /** * Returns true if we have a cached record that the permission identified by * `key` is valid and unexpired. */ private isPermissionCached; /** Caches the fact that the permission for `key` is valid until `expiry`. */ private cachePermission; /** Records that a non-spending permission was just granted so we can skip re-prompting briefly. */ private markRecentGrant; /** Returns true if we are inside the short "cover window" immediately after granting permission. */ private isRecentlyGranted; /** * Normalizes originator domains to their lowercase hostname. BRC-100 * permission authority is hostname-scoped, so every port shares the same * grants and admin status. */ private normalizeOriginator; private isWhitelistedCounterpartyProtocol; /** * Produces a normalized originator value along with the set of legacy * representations that should be considered when searching for existing * permission tokens (for backwards compatibility). */ private prepareOriginator; /** * Builds a unique list of originator variants that should be searched when * looking up on-chain tokens (e.g., legacy raw + normalized forms). */ private buildOriginatorLookupValues; /** * Builds a "map key" string so that identical requests (e.g. "protocol:domain:true:protoName:counterparty") * do not produce multiple user prompts. */ private buildRequestKey; private buildActiveRequestKey; } //# sourceMappingURL=WalletPermissionsManager.d.ts.map