The core permission module for BTMS token operations. Framework-agnostic with no UI dependencies.
BSV Desktop and BSV Browser show a spend authorization modal whenever BSV is spent. For a BTMS token output the raw satoshi value is typically 1 sat — not the token's actual denomination. This module gives the wallet enough context to show the correct value to the user and gate authorization appropriately. A USD stablecoin issuer, for example, ships a module that causes the modal to display "$1.00 USD" rather than "1 satoshi."
@bsv/btms-permission-module implements the BRC-98/99 permission hooks interface to intercept BTMS token spend and burn operations, prompt users via a callback, and enforce authorization decisions. Works with any UI framework (React, Vue, Angular, vanilla JS, or no UI at all).
npm install @bsv/btms-permission-moduleimport { createBtmsModule } from '@bsv/btms-permission-module'
import { createWallet } from '@bsv/simple'
const wallet = await createWallet()
const requestTokenAccess = async (app: string, message: string): Promise<boolean> => {
const details = JSON.parse(message)
const approved = confirm(
`${app} wants to ${details.operation} ${details.sendAmount || details.burnAmount} of "${details.tokenName}"`
)
return approved
}
const basicTokenModule = createBtmsModule({
wallet,
promptHandler: requestTokenAccess
})BasicTokenModule implementing BRC-98/99 canPerform() and promptUser() hookscreateBtmsModule() for convenient BTMS + module initializationPermissionPromptHandler callback pattern for custom UI integrationimport { createBtmsModule } from '@bsv/btms-permission-module'
import { createWallet } from '@bsv/simple'
const wallet = await createWallet()
const requestTokenAccess = async (app: string, message: string): Promise<boolean> => {
const details = JSON.parse(message)
const approved = confirm(
`${app} wants to ${details.operation} ${details.sendAmount || details.burnAmount} of "${details.tokenName}"`
)
return approved
}
const basicTokenModule = createBtmsModule({
wallet,
promptHandler: requestTokenAccess
})import { createBtmsModule } from '@bsv/btms-permission-module'
// Create module with no prompt handler — all requests denied
const module = createBtmsModule({
wallet
// No promptHandler → defaults to deny all
})
// Useful for server-side or automated workflowsimport { WalletPermissionsManager } from '@bsv/wallet-toolbox'
import { createBtmsModule } from '@bsv/btms-permission-module'
const tokenModule = createBtmsModule({
wallet,
promptHandler: myPromptHandler
})
const permissionsManager = new WalletPermissionsManager(wallet, appOrigin, {
permissionModules: {
btms: tokenModule // Register under 'btms' key
}
})
// Now when app tries to spend BTMS tokens, permission system will:
// 1. Check if app has permission for 'btms' protocol
// 2. Call module's promptUser() if permission not cached
// 3. Ask user via your prompt handler
// 4. Cache decision for sessionWalletPermissionsManager caches yes/no decisions per (app, protocol) for the session.{ tokenName?, assetId, sendAmount?, burnAmount?, recipientKey?, operation: 'spend' | 'burn' }canPerform() and promptUser())JSON parse errors — If the message format is wrong,
JSON.parse()will throw. Always wrap in try/catch in production handlers.
Async handler blocking — If your prompt handler takes too long, the wallet operation times out. Keep handlers responsive.
Promise never resolving — If your handler never calls
resolve(), the wallet operation hangs. Always ensure resolve/reject is called.
Handler called multiple times — For a single token send, handler may be called once per output. Batch prompts if possible in your UI.
No token name available — If asset hasn't been discovered yet, tokenName may be undefined. Use assetId as fallback for display.