名称:钱包-brc100 描述:当用户询问“实现 BRC-100 钱包”、“使用钱包工具箱”、“TypeScript BSV 钱包”、“BRC-100 实现”、“桌面钱包”、“Electron 钱包”、“浏览器钱包”、“IndexedDB 钱包存储”、“钱包操作”、“钱包篮子”、“UTXO 管理”、“createAction”、“listOutputs”、“钱包证书”,或需要指导使用 @bsv/wallet-toolbox 构建符合标准的钱包时,应使用此技能。
BRC-100 钱包实现指南
此技能提供使用 @bsv/wallet-toolbox 包(v1.7.18+)实现 BRC-100 兼容钱包的全面指导。
入门指南:在实现之前,请查看战略问卷以确定适合您钱包类型的架构。
快速参考
核心依赖
{
"@bsv/wallet-toolbox": "^1.7.18",
"@bsv/sdk": "^1.9.29"
}
主要类
| 类 | 目的 | 使用场景 |
|---|---|---|
| Wallet | 完整的 BRC-100 钱包 | 构建生产级钱包应用 |
| SimpleWalletManager | 轻量级包装器 | 简单的基于密钥的身份验证 |
| CWIStyleWalletManager | 多配置文件钱包 | 高级 UMP 代币流程 |
| WalletSigner | 交易签名 | 自定义签名逻辑 |
目录
1. 安装与设置
安装依赖
npm install @bsv/wallet-toolbox @bsv/sdk
# 可选存储后端:
npm install knex sqlite3 # SQLite
npm install knex mysql2 # MySQL
npm install idb # IndexedDB(浏览器)
基本导入
import {
Wallet,
WalletStorageManager,
StorageKnex,
StorageIdb,
Services,
WalletServices,
PrivilegedKeyManager
} from '@bsv/wallet-toolbox'
import {
PrivateKey,
KeyDeriver,
Random,
Utils
} from '@bsv/sdk'
2. 钱包初始化
模式 A:简单钱包(Node.js 与 SQLite)
import { Wallet, StorageKnex, Services } from '@bsv/wallet-toolbox'
import { PrivateKey, Random } from '@bsv/sdk'
import Knex from 'knex'
async function createSimpleWallet() {
// 1. 创建根私钥(或从助记词派生)
const rootKey = new PrivateKey(Random(32))
// 使用 @bsv/sdk 的 KeyDeriver 进行正确的 BRC-42 密钥派生
const keyDeriver = new KeyDeriver(rootKey)
// 2. 配置 SQLite 存储
const knex = Knex({
client: 'sqlite3',
connection: { filename: './wallet.db' },
useNullAsDefault: true
})
const storage = new StorageKnex({
knex,
storageIdentityKey: rootKey.toPublicKey().toString(),
storageName: 'my-wallet-storage'
})
await storage.makeAvailable()
// 3. 配置服务(主网)
const services = new Services({
chain: 'main',
bsvExchangeRate: { timestamp: new Date(), base: 'USD', rate: 50 },
bsvUpdateMsecs: 15 * 60 * 1000,
fiatExchangeRates: {
timestamp: new Date(),
base: 'USD',
rates: { EUR: 0.85, GBP: 0.73 }
},
fiatUpdateMsecs: 24 * 60 * 60 * 1000,
arcUrl: 'https://arc.taal.com',
arcConfig: {}
})
// 4. 创建钱包
const wallet = new Wallet({
chain: 'main',
keyDeriver,
storage,
services
})
return wallet
}
模式 B:浏览器钱包(IndexedDB)
import { Wallet, StorageIdb, Services } from '@bsv/wallet-toolbox'
import { PrivateKey, Random } from '@bsv/sdk'
async function createBrowserWallet() {
const rootKey = new PrivateKey(Random(32))
// 使用 IndexedDB 作为浏览器存储
const storage = new StorageIdb({
idb: await openDB('my-wallet-db', 1),
storageIdentityKey: rootKey.toPublicKey().toString(),
storageName: 'browser-wallet'
})
await storage.makeAvailable()
const services = new Services({
chain: 'main',
// ... 服务配置
})
const wallet = new Wallet({
chain: 'main',
keyDeriver: createKeyDeriver(rootKey),
storage,
services
})
return wallet
}
模式 C:多配置文件钱包
import { CWIStyleWalletManager, OverlayUMPTokenInteractor } from '@bsv/wallet-toolbox'
async function createMultiProfileWallet() {
const manager = new CWIStyleWalletManager(
'example.com', // 管理员发起者
async (profilePrimaryKey, profilePrivilegedKeyManager, profileId) => {
// 为特定配置文件构建钱包
const keyDeriver = createKeyDeriver(new PrivateKey(profilePrimaryKey))
const storage = await createStorage(profileId)
const services = new Services({ chain: 'main', /* ... */ })
return new Wallet({
chain: 'main',
keyDeriver,
storage,
services,
privilegedKeyManager: profilePrivilegedKeyManager
})
},
new OverlayUMPTokenInteractor(), // UMP 代币交互器
async (recoveryKey) => {
// 保存恢复密钥(例如,提示用户记下)
console.log('保存此恢复密钥:', Utils.toBase64(recoveryKey))
return true
},
async (reason, test) => {
// 从用户获取密码
const password = prompt(`输入密码原因:${reason}`)
if (!password) throw new Error('需要密码')
if (!test(password)) throw new Error('密码无效')
return password
}
)
// 提供展示密钥(例如,从二维码扫描)
const presentationKey = Random(32)
await manager.providePresentationKey(presentationKey)
// 提供密码
await manager.providePassword('user-password')
// 现在已认证并准备使用
return manager
}
3. 交易操作
创建交易
import { CreateActionArgs, CreateActionResult } from '@bsv/sdk'
async function sendBSV(
wallet: Wallet,
recipientAddress: string,
satoshis: number
) {
const args: CreateActionArgs = {
description: '发送 BSV 支付',
outputs: [{
lockingScript: Script.fromAddress(recipientAddress).toHex(),
satoshis,
outputDescription: `支付给 ${recipientAddress}`,
basket: 'default',
tags: ['payment']
}],
options: {
acceptDelayedBroadcast: false, // 立即广播
randomizeOutputs: true // 隐私
}
}
const result: CreateActionResult = await wallet.createAction(args)
if (result.txid) {
console.log('交易已创建:', result.txid)
return result.txid
} else {
console.log('交易待签名')
return result.signableTransaction
}
}
签名交易
async function signTransaction(
wallet: Wallet,
reference: string,
unlockingScripts: Record<number, { unlockingScript: string }>
) {
const result = await wallet.signAction({
reference,
spends: unlockingScripts
})
console.log('交易已签名:', result.txid)
return result
}
检查钱包余额
async function getWalletBalance(wallet: Wallet) {
// 方法 1:快速余额(使用特殊操作)
const balance = await wallet.balance()
console.log(`余额:${balance} satoshis`)
// 方法 2:带 UTXO 的详细余额
const detailed = await wallet.balanceAndUtxos('default')
console.log(`总计:${detailed.total} satoshis`)
console.log(`UTXO 数量:${detailed.utxos.length}`)
detailed.utxos.forEach(utxo => {
console.log(` ${utxo.outpoint}: ${utxo.satoshis} sats`)
})
return balance
}
列出输出
import { ListOutputsArgs, ListOutputsResult } from '@bsv/sdk'
async function listSpendableOutputs(wallet: Wallet) {
const args: ListOutputsArgs = {
basket: 'default', // 更改篮子
spendable: true, // 仅可花费输出
limit: 100,
offset: 0,
tags: ['payment'] // 可选:按标签过滤
}
const result: ListOutputsResult = await wallet.listOutputs(args)
console.log(`找到 ${result.totalOutputs} 个输出`)
result.outputs.forEach(output => {
console.log(` ${output.outpoint}: ${output.satoshis} sats`)
})
return result
}
列出操作(交易)
async function listTransactionHistory(wallet: Wallet) {
const result = await wallet.listActions({
labels: [],
labelQueryMode: 'any',
limit: 50,
offset: 0
})
console.log(`找到 ${result.totalActions} 个操作`)
result.actions.forEach(action => {
console.log(` ${action.txid}: ${action.status} - ${action.description}`)
})
return result
}
4. 密钥管理
获取公钥
async function getIdentityKey(wallet: Wallet) {
// 获取钱包的身份密钥
const result = await wallet.getPublicKey({ identityKey: true })
console.log('身份密钥:', result.publicKey)
return result.publicKey
}
async function getDerivedKey(wallet: Wallet) {
// 获取特定协议的派生密钥
const result = await wallet.getPublicKey({
protocolID: [2, 'my-app'],
keyID: 'encryption-key-1',
counterparty: 'recipient-identity-key'
})
return result.publicKey
}
加密/解密数据
async function encryptMessage(
wallet: Wallet,
plaintext: string,
recipientPubKey: string
) {
const result = await wallet.encrypt({
plaintext: Utils.toArray(plaintext, 'utf8'),
protocolID: [2, 'secure-messaging'],
keyID: 'msg-key',
counterparty: recipientPubKey
})
return Utils.toBase64(result.ciphertext)
}
async function decryptMessage(
wallet: Wallet,
ciphertext: string,
senderPubKey: string
) {
const result = await wallet.decrypt({
ciphertext: Utils.toArray(ciphertext, 'base64'),
protocolID: [2, 'secure-messaging'],
keyID: 'msg-key',
counterparty: senderPubKey
})
return Utils.toUTF8(result.plaintext)
}
创建签名
async function signData(wallet: Wallet, data: string) {
const result = await wallet.createSignature({
data: Utils.toArray(data, 'utf8'),
protocolID: [2, 'document-signing'],
keyID: 'sig-key',
counterparty: 'self'
})
return Utils.toBase64(result.signature)
}
5. 存储配置
SQLite 存储(Node.js)
import Knex from 'knex'
import { StorageKnex } from '@bsv/wallet-toolbox'
async function setupSQLiteStorage() {
const knex = Knex({
client: 'sqlite3',
connection: { filename: './wallet.db' },
useNullAsDefault: true
})
const storage = new StorageKnex({
knex,
storageIdentityKey: 'your-identity-key',
storageName: 'main-storage'
})
await storage.makeAvailable()
return storage
}
MySQL 存储
async function setupMySQLStorage() {
const knex = Knex({
client: 'mysql2',
connection: {
host: 'localhost',
user: 'wallet_user',
password: 'secure_password',
database: 'wallet_db'
}
})
const storage = new StorageKnex({
knex,
storageIdentityKey: 'your-identity-key',
storageName: 'mysql-storage'
})
await storage.makeAvailable()
return storage
}
IndexedDB 存储(浏览器)
import { openDB, DBSchema } from 'idb'
import { StorageIdb } from '@bsv/wallet-toolbox'
interface WalletDB extends DBSchema {
// 存储模式由 StorageIdb 管理
}
async function setupIndexedDBStorage() {
const db = await openDB<WalletDB>('wallet-db', 1, {
upgrade(db) {
// StorageIdb 创建必要的对象存储
}
})
const storage = new StorageIdb({
idb: db,
storageIdentityKey: 'your-identity-key',
storageName: 'browser-storage'
})
await storage.makeAvailable()
return storage
}
多存储管理器
import { WalletStorageManager } from '@bsv/wallet-toolbox'
async function setupMultiStorage() {
const primaryStorage = await setupSQLiteStorage()
const backupStorage = await setupMySQLStorage()
const manager = new WalletStorageManager(
primaryStorage,
[backupStorage]
)
return manager
}
6. 证书操作
获取证书(直接协议)
import { AcquireCertificateArgs } from '@bsv/sdk'
async function acquireDirectCertificate(wallet: Wallet) {
const args: AcquireCertificateArgs = {
acquisitionProtocol: 'direct',
type: 'https://example.com/user-certificate',
certifier: 'certifier-identity-key',
serialNumber: Utils.toArray('cert-serial-123', 'utf8'),
subject: await wallet.getIdentityKey(),
revocationOutpoint: 'txid.vout',
fields: {
name: Utils.toArray('Alice Smith', 'utf8'),
email: Utils.toArray('alice@example.com', 'utf8')
},
keyringForSubject: { /* 主密钥环 */ },
signature: Utils.toArray('signature-bytes', 'base64')
}
const result = await wallet.acquireCertificate(args)
console.log('证书已获取:', result.certificateId)
return result
}
获取证书(发行协议)
async function requestCertificateIssuance(wallet: Wallet) {
const args: AcquireCertificateArgs = {
acquisitionProtocol: 'issuance',
type: 'https://example.com/kyc-certificate',
certifier: 'certifier-identity-key',
certifierUrl: 'https://certifier.example.com',
fields: {
name: 'Alice Smith',
birthdate: '1990-01-01',
country: 'US'
}
}
const result = await wallet.acquireCertificate(args)
console.log('证书已发行:', result.certificateId)
return result
}
列出证书
async function listMyCertificates(wallet: Wallet) {
const result = await wallet.listCertificates({
certifiers: ['certifier-identity-key'],
types: ['https://example.com/user-certificate'],
limit: 50,
offset: 0
})
console.log(`找到 ${result.totalCertificates} 个证书`)
result.certificates.forEach(cert => {
console.log(` 类型:${cert.type}, 认证者:${cert.certifier}`)
})
return result
}
证明证书
async function proveCertificate(wallet: Wallet, certificateId: string) {
const result = await wallet.proveCertificate({
certificateId,
fieldsToReveal: ['name', 'email'],
verifier: 'verifier-identity-key',
privileged: false
})
console.log('证书证明:', result.keyringForVerifier)
return result
}
7. 错误处理
标准错误类型
import {
WalletError,
WERR_INVALID_PARAMETER,
WERR_INTERNAL,
WERR_REVIEW_ACTIONS
} from '@bsv/wallet-toolbox'
try {
const result = await wallet.createAction({
description: '测试交易',
outputs: [/* ... */]
})
} catch (eu: unknown) {
const error = WalletError.fromUnknown(eu)
if (error.name === 'WERR_INVALID_PARAMETER') {
console.error('无效参数:', error.message)
console.error('堆栈:', error.stack)
} else if (error.name === 'WERR_REVIEW_ACTIONS') {
// 处理交易审核错误
console.error('需要审核:', error.details)
} else {
console.error('钱包错误:', error.message)
}
}
审核操作错误(交易失败)
async function handleCreateAction(wallet: Wallet) {
try {
return await wallet.createAction({
description: '支付',
outputs: [/* ... */]
})
} catch (eu: unknown) {
const error = WalletError.fromUnknown(eu)
if (error.name === 'WERR_REVIEW_ACTIONS') {
// 访问详细失败信息
const details = error as any
console.error('延迟结果:', details.notDelayedResults)
console.error('发送结果:', details.sendWithResults)
console.error('失败 txid:', details.txid)
// 处理双重花费
if (details.notDelayedResults?.some(r => r.status === 'doubleSpend')) {
console.error('检测到双重花费!')
console.error('竞争交易:', details.notDelayedResults[0].competingTxs)
}
}
throw error
}
}
8. 生产模式
模式:钱包状态管理
class WalletManager {
private wallet: Wallet | null = null
async initialize(rootKey: PrivateKey) {
if (this.wallet) {
throw new Error('钱包已初始化')
}
const storage = await this.setupStorage()
const services = this.setupServices()
const keyDeriver = this.createKeyDeriver(rootKey)
this.wallet = new Wallet({
chain: 'main',
keyDeriver,
storage,
services
})
return this.wallet
}
async destroy() {
if (this.wallet) {
await this.wallet.destroy()
this.wallet = null
}
}
getWallet(): Wallet {
if (!this.wallet) {
throw new Error('钱包未初始化')
}
return this.wallet
}
private async setupStorage() {
// 存储设置逻辑
return await setupSQLiteStorage()
}
private setupServices() {
return new Services({
chain: 'main',
// ... 配置
})
}
private createKeyDeriver(rootKey: PrivateKey) {
// 密钥派生逻辑
return {
rootKey,
identityKey: rootKey.toPublicKey().toString(),
// ... 派生方法
}
}
}
模式:交易重试逻辑
async function sendWithRetry(
wallet: Wallet,
args: CreateActionArgs,
maxRetries = 3
): Promise<string> {
let lastError: Error | null = null
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await wallet.createAction(args)
if (result.txid) {
return result.txid
}
// 如果需要,处理签名
if (result.signableTransaction) {
const signed = await wallet.signAction({
reference: result.signableTransaction.reference,
spends: {} // 提供解锁脚本
})
return signed.txid!
}
throw new Error('意外结果格式')
} catch (error) {
lastError = error as Error
console.error(`尝试 ${attempt} 失败:`, error)
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
}
}
}
throw lastError || new Error('所有重试失败')
}
模式:后台交易监控
import { Monitor } from '@bsv/wallet-toolbox'
async function setupMonitor(wallet: Wallet) {
const monitor = new Monitor({
storage: wallet.storage,
services: wallet.services,
chain: 'main'
})
monitor.on('transaction', (status) => {
console.log('交易更新:', status.txid, status.blockHeight)
})
monitor.on('error', (error) => {
console.error('监控错误:', error)
})
await monitor.start()
return monitor
}
相关技能
对于全面的钱包开发,还参考以下技能:
| 技能 | 关系 |
|---|---|
encrypt-decrypt-backup |
标准备份格式(.bep 文件,AES-256-GCM) |
junglebus |
从区块链填充 UTXO 集,实时流 |
key-derivation |
Type42/BRC-42 和 BIP32 密钥派生细节 |
wallet-encrypt-decrypt |
ECDH 消息加密模式 |
wallet-send-bsv |
基本交易创建(比 BRC-100 更简单) |
对于 1Sat Ordinals / 代币支持:
如果您的 BRC-100 钱包需要处理 1Sat Ordinals、BSV-20/BSV-21 代币或铭文,请使用 @1sat/wallet-toolbox,它在核心钱包工具箱上包装了 ordinals 功能。
参见 1sat-skills:
wallet-create-ordinals- 铸造铭文extract-blockchain-media- 从交易中提取媒体ordinals-marketplace- 浏览 GorillaPool 市场
附加资源
- BRC-100 规范:https://bsv.brc.dev/wallet/0100
- BRC-42 (BKDS):https://bsv.brc.dev/wallet/0042
- BRC-43 (安全级别):https://bsv.brc.dev/wallet/0043
- 钱包工具箱文档:https://bsv-blockchain.github.io/wallet-toolbox
- BSV SDK 文档:https://bsv-blockchain.github.io/ts-sdk
- @1sat/wallet-toolbox:支持 1Sat Ordinals 的 BRC-100 钱包(包装 @bsv/wallet-toolbox)
- 1sat-skills:https://github.com/b-open-io/1sat-skills - Ordinals 铸造和管理
- bsv-desktop(参考实现):https://github.com/bsv-blockchain/bsv-desktop
- 具有 BRC-100 支持的真实世界 Electron 钱包
- 用于存储隔离的 IPC 架构
- 后台监控模式
- 在端口 2121 上运行 HTTPS 服务器用于 BRC-100 接口
研究:对于 BRC 规范或实现模式的深入研究,请使用浏览器代理从 bsv.brc.dev 获取当前文档。
平台指南
特定于平台的实现指南:
| 平台 | 指南 | 参考实现 |
|---|---|---|
| 浏览器扩展 | extension-guide.md | yours-wallet |
| 桌面(Electron) | desktop-guide.md | bsv-desktop |
| Web 应用 | web-guide.md | - |
| 移动(React Native) | mobile-guide.md | - |
| Node.js 服务/CLI | nodejs-guide.md | - |
参见 references/key-concepts.md 了解 BRC-100 独特概念:
- 操作与交易
- 篮子和标签
- 证书系统(BRC-52/53/64/65)
- 后台监控
常见模式总结
| 任务 | 方法 | 关键参数 |
|---|---|---|
| 发送 BSV | createAction() |
outputs, options |
| 检查余额 | balance() |
无 |
| 列出 UTXO | listOutputs() |
basket, spendable |
| 获取历史 | listActions() |
labels, limit |
| 获取公钥 | getPublicKey() |
protocolID, keyID |
| 加密数据 | encrypt() |
plaintext, counterparty |
| 获取证书 | acquireCertificate() |
type, certifier |
记住:始终正确处理错误,安全使用特权密钥,并遵循 BRC-100 安全级别进行敏感操作!