@bsv/wallet-toolbox is the reference toolkit for building BRC-100 wallets. It connects @bsv/sdk primitives to wallet storage, key derivation, signing, services, monitoring, permissions, and authentication flows.
Use this package when you are building a wallet product, a wallet-like service, or another implementation that must match BRC-100 behavior.
Knex and IndexedDB listOutputs providers report totalOutputs as the full
matching count on every page, including short final and out-of-range pages.
WalletAuthenticationManager supports an additive WAB UMP outpoint pin for
legacy ambiguity and an OTP-verified phone-number change that always rolls the
presentation key. The same registered number is valid. A pin is ignored unless
normal verified lineage resolution remains ambiguous and the outpoint is one
of the wallet's verified candidates. Applications must persist
saveSnapshot() immediately after completePhoneNumberChange() succeeds.
Action-batch workspaces now admit only explicitly connected transaction-graph members. Unrelated actions stay on their ordinary storage path, while related workspaces can resume an expired soft lease by reacquiring only their exact persisted inputs under the provider's advertised reservation bound.
Immediate actions may use wallet-managed change from a transaction awaiting background broadcast, but only after completed and unproven liquidity is exhausted or an over-16-input settled plan is larger by exact serialized transaction-plus-BEEF cost. Queued funds are never hidden.
Durable permission grants retain delayed broadcast, avoiding network latency in the permission path. New and existing wallets progressively target 144 useful 5,000-satoshi change outputs, create no more than eight outputs per action, and migrate no more than four fee-positive legacy fragments per action. Optional shaping cannot make a formerly fundable action fail.
Completed createAction and signAction results expose Atomic BEEF as a
numeric array at the public wallet boundary. The historical shape survives
plain JSON serialization for older BRC-100 applications; typed arrays remain
supported by the AtomicBEEF type and binary Wallet Wire transports.
WalletStorageManager.getStores() reports the configured endpointURL for
remote providers without relying on a class name. Browser and application
bundlers may safely minify the provider constructor while backup selection and
make-primary flows continue matching the original endpoint URL.
Opt-in remote-storage timing spans retain trace and parent-span correlation in the telemetry sink without adding headers to authenticated requests. BRC-103, BRC-104, AuthFetch, and the storage RPC wire contract remain unchanged.
UMP account lookup accepts one verified matching token as an existing account. When no token verifies, one clean empty overlay response establishes a new account even if other hosts fail or return malformed records. Multiple distinct verified tokens remain errors unless normal lineage finds one current token or an optional WAB pin names one of the verified candidates. Lookups with no usable response remain errors; WAB existing-account continuity still prevents replacement-wallet onboarding.
ChainTracks defaults to credential-free Arcade/go-chaintracks v2 HTTP and SSE on mainnet, testnet, and TerraTestNet. STN and Terra Scaling TestNet require an explicit operator endpoint. Remote header batches pass local serialization, hash, continuity, and genesis checks; source failures fall through in priority order; and synchronized trackers keep serving last-good local data. WhatsOnChain is an optional, rate-limited mainnet/testnet fallback; no key is required.
Local ChainTracks height reads now use stale-while-revalidate singleflight,
while immutable bulk objects coalesce misses and back off failed loads. Node
services can move complete length, digest, linkage, chain-work, genesis, and
proof-of-work validation into NodeBulkFileDataValidator; filesystem
deployments can pair content-addressed quarantine storage with a crash-safe,
per-attempt DurableFileBulkFileDownloadBudget.
npm install @bsv/wallet-toolboxBrowser and mobile bundles are also published:
npm install @bsv/wallet-toolbox-client
npm install @bsv/wallet-toolbox-mobile| Component | Purpose |
|---|---|
Wallet | Main BRC-100 implementation. |
WalletStorageManager | Coordinates active and backup storage providers. |
| Storage providers | SQL/Knex, IndexedDB, and remote storage over HTTP. |
WalletSigner | Bridges wallet-controlled keys into SDK transaction signing flows. |
Services | Network service container for broadcast, chain tracking, and proof services. |
Monitor | Background wallet maintenance tasks. |
| Key managers | BRC-42/43 derivation, privileged key management, Shamir-based recovery flows. |
WalletPermissionsManager | Permission gating around wallet methods and reserved protocols/baskets. |
MockChain | Test chain utilities for wallet behavior without a live network. |
The example package uses the Setup class for wallet construction. Create a .env with Setup.makeEnv(), then load the environment and construct a client wallet:
import { Setup } from '@bsv/wallet-toolbox'
const env = Setup.getEnv('test')
const setup = await Setup.createWalletClient({
env,
endpointUrl: 'https://store-us-1.bsvb.tech'
})
const { publicKey } = await setup.wallet.getPublicKey({
identityKey: true
})
console.log(publicKey)setup.wallet is the BRC-100 wallet. The surrounding setup object exposes the constructed rootKey, identityKey, keyDeriver, storage, services, and monitor so wallet builders can inspect or replace pieces while developing.
When every input can be signed by the wallet, createAction can return a completed action:
export async function createP2pkhOutput(recipientAddress: string) {
const lockingScript = Setup.getLockP2PKH(recipientAddress).toHex()
const result = await setup.wallet.createAction({
description: 'Create payment',
labels: ['payment'],
outputs: [
{
lockingScript,
satoshis: 1000,
outputDescription: 'Payment output'
}
],
options: {
randomizeOutputs: false,
acceptDelayedBroadcast: false
}
})
console.log(result.txid, result.tx)
}
await createP2pkhOutput('1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX')When an explicit input needs an unlocking script supplied by the caller, createAction returns signableTransaction, then signAction completes it:
export async function finishCustomSpend(args: {
inputBEEF: number[]
outpoint: string
lockingScript: string
unlockingScript: string
}) {
const created = await setup.wallet.createAction({
description: 'Spend custom input',
inputBEEF: args.inputBEEF,
inputs: [
{
outpoint: args.outpoint,
unlockingScriptLength: 108,
inputDescription: 'Custom input'
}
],
outputs: [
{
lockingScript: args.lockingScript,
satoshis: 1000,
outputDescription: 'Payment output'
}
]
})
await setup.wallet.signAction({
reference: created.signableTransaction!.reference,
spends: {
0: { unlockingScript: args.unlockingScript }
},
options: { acceptDelayedBroadcast: false }
})
}See packages/wallet/wallet-toolbox-examples/src/p2pkh.ts, brc29.ts, pushdrop.ts, and nosend.ts for complete source-backed flows.
| Model | Use |
|---|---|
| SQL/Knex | Node.js wallets and servers with SQLite, MySQL, or another Knex-supported database. |
| IndexedDB | Browser and mobile wallets that keep state on-device. |
| Remote storage | Wallet clients that delegate storage to a Wallet Infra endpoint such as https://store-us-1.bsvb.tech. |
createAction, signAction, listOutputs, internalizeAction, and no-send batching.@bsv/simple/browser for ordinary web app integration.@bsv/simple/server for a backend agent with a private key.@bsv/sdk for raw crypto, scripts, transactions, BEEF, or the BRC-100 interface types.