BRC-100Go钱包实现Skill wallet-brc100-go

这是一个关于使用Go语言实现BRC-100标准区块链钱包的技能指南。它提供了完整的代码示例和步骤,涵盖钱包初始化、交易操作、密钥管理、存储配置等,帮助开发者快速构建BSV区块链上的合规加密钱包。关键词:Go语言, 区块链钱包, BRC-100, BSV, 加密技术, 钱包开发, 数字资产

链开发 0 次安装 0 次浏览 更新于 3/15/2026

名称: wallet-brc100-go 描述: 当用户要求“用Go实现BRC-100钱包”、“使用go-wallet-toolbox”、“Go BSV钱包”、“BRC-100 Go实现”,或需要指导使用Go wallet-toolbox构建合规钱包时,应使用此技能。

BRC-100钱包实现指南(Go)

使用go-wallet-toolbox包实现BRC-100合规钱包的综合指南。

🎯 快速参考

核心依赖

import (
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/wallet"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/storage"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/services"
    sdk "github.com/bsv-blockchain/go-sdk/wallet"
    "github.com/bsv-blockchain/go-sdk/primitives/ec"
    "github.com/bsv-blockchain/go-sdk/transaction"
)

安装

go get github.com/bsv-blockchain/go-wallet-toolbox
go get github.com/bsv-blockchain/go-sdk

📚 目录

  1. 钱包初始化
  2. 交易操作
  3. 密钥管理
  4. 存储配置
  5. 证书操作
  6. 错误处理
  7. 生产模式

1. 钱包初始化

模式A:简单钱包设置

package main

import (
    "context"
    "log"

    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/wallet"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/storage"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/services"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/defs"
    sdk "github.com/bsv-blockchain/go-sdk/wallet"
    "github.com/bsv-blockchain/go-sdk/primitives/ec"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

func createWallet() (*wallet.Wallet, error) {
    ctx := context.Background()

    // 1. 生成根密钥(或从助记词派生)
    rootKey, err := ec.NewPrivateKey()
    if err != nil {
        return nil, err
    }

    // 2. 创建密钥派生器
    keyDeriver := sdk.NewKeyDeriver(rootKey)

    // 3. 设置SQLite存储
    db, err := gorm.Open(sqlite.Open("wallet.db"), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    storageOpts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: rootKey.PubKey().Compressed(),
        StorageName:        "main-wallet",
    }

    walletStorage, err := storage.NewStorage(storageOpts)
    if err != nil {
        return nil, err
    }

    // 4. 设置服务(主网)
    servicesOpts := &services.Options{
        Network: defs.Mainnet,
        ArcURL:  "https://arc.taal.com",
        WocURL:  "https://api.whatsonchain.com/v1/bsv/main",
    }

    walletServices, err := services.NewServices(ctx, servicesOpts)
    if err != nil {
        return nil, err
    }

    // 5. 创建钱包
    w, err := wallet.NewWallet(
        ctx,
        keyDeriver,
        walletStorage,
        wallet.WithServices(walletServices),
        wallet.WithNetwork(defs.Mainnet),
    )
    if err != nil {
        return nil, err
    }

    return w, nil
}

模式B:使用MySQL存储的钱包

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

func createMySQLWallet(ctx context.Context, rootKey *ec.PrivateKey) (*wallet.Wallet, error) {
    // MySQL DSN
    dsn := "user:password@tcp(127.0.0.1:3306)/wallet_db?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    storageOpts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: rootKey.PubKey().Compressed(),
        StorageName:        "mysql-wallet",
    }

    walletStorage, err := storage.NewStorage(storageOpts)
    if err != nil {
        return nil, err
    }

    keyDeriver := sdk.NewKeyDeriver(rootKey)
    walletServices, err := services.NewServices(ctx, &services.Options{
        Network: defs.Mainnet,
        ArcURL:  "https://arc.taal.com",
    })
    if err != nil {
        return nil, err
    }

    return wallet.NewWallet(
        ctx,
        keyDeriver,
        walletStorage,
        wallet.WithServices(walletServices),
        wallet.WithNetwork(defs.Mainnet),
    )
}

模式C:测试网钱包

func createTestnetWallet(ctx context.Context) (*wallet.Wallet, error) {
    rootKey, _ := ec.NewPrivateKey()
    keyDeriver := sdk.NewKeyDeriver(rootKey)

    db, _ := gorm.Open(sqlite.Open("testnet.db"), &gorm.Config{})
    storageOpts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: rootKey.PubKey().Compressed(),
        StorageName:        "testnet-wallet",
    }
    walletStorage, _ := storage.NewStorage(storageOpts)

    // 测试网服务
    walletServices, err := services.NewServices(ctx, &services.Options{
        Network: defs.Testnet,
        ArcURL:  "https://arc-test.taal.com",
        WocURL:  "https://api.whatsonchain.com/v1/bsv/test",
    })
    if err != nil {
        return nil, err
    }

    return wallet.NewWallet(
        ctx,
        keyDeriver,
        walletStorage,
        wallet.WithServices(walletServices),
        wallet.WithNetwork(defs.Testnet),
    )
}

2. 交易操作

创建交易

import (
    "github.com/bsv-blockchain/go-sdk/script"
    sdk "github.com/bsv-blockchain/go-sdk/wallet"
)

func sendBSV(
    ctx context.Context,
    w *wallet.Wallet,
    recipientAddress string,
    satoshis uint64,
) (string, error) {
    // 从地址构建锁定脚本
    lockingScript, err := script.NewP2PKHFromAddress(recipientAddress)
    if err != nil {
        return "", err
    }

    // 创建操作参数
    args := &sdk.CreateActionArgs{
        Description: "发送BSV支付",
        Outputs: []sdk.CreateActionOutput{
            {
                LockingScript:    lockingScript.String(),
                Satoshis:         satoshis,
                OutputDescription: fmt.Sprintf("支付给 %s", recipientAddress),
                Basket:            "default",
                Tags:              []string{"payment"},
            },
        },
        Options: &sdk.CreateActionOptions{
            AcceptDelayedBroadcast: false, // 立即广播
            RandomizeOutputs:       true,  // 隐私保护
        },
    }

    // 创建操作
    result, err := w.CreateAction(ctx, args)
    if err != nil {
        return "", err
    }

    if result.TxID != nil {
        return *result.TxID, nil
    }

    // 如果需要签名,处理签名
    if result.SignableTransaction != nil {
        return signAndFinalize(ctx, w, result.SignableTransaction)
    }

    return "", fmt.Errorf("意外的结果格式")
}

签名交易

func signTransaction(
    ctx context.Context,
    w *wallet.Wallet,
    reference string,
    unlockingScripts map[uint32]sdk.UnlockingScriptSend,
) (*sdk.SignActionResult, error) {
    args := &sdk.SignActionArgs{
        Reference: reference,
        Spends:    unlockingScripts,
    }

    result, err := w.SignAction(ctx, args)
    if err != nil {
        return nil, err
    }

    return result, nil
}

检查钱包余额

func getBalance(ctx context.Context, w *wallet.Wallet) (uint64, error) {
    // 使用特殊操作快速获取余额
    args := &sdk.ListOutputsArgs{
        Basket: "00000000000000000000000000000000", // 余额的特殊篮子
    }

    result, err := w.ListOutputs(ctx, args)
    if err != nil {
        return 0, err
    }

    return uint64(result.TotalOutputs), nil
}

// 获取带UTXO的详细余额
func getDetailedBalance(ctx context.Context, w *wallet.Wallet) (*sdk.ListOutputsResult, error) {
    args := &sdk.ListOutputsArgs{
        Basket:    "default",
        Spendable: to.Ptr(true),
        Limit:     to.Ptr(uint32(100)),
        Offset:    to.Ptr(uint32(0)),
    }

    result, err := w.ListOutputs(ctx, args)
    if err != nil {
        return nil, err
    }

    log.Printf("找到 %d 个可花费输出", len(result.Outputs))
    for _, output := range result.Outputs {
        log.Printf("  %s: %d satoshis", output.Outpoint, output.Satoshis)
    }

    return result, nil
}

列出交易历史

func listTransactions(ctx context.Context, w *wallet.Wallet) (*sdk.ListActionsResult, error) {
    args := &sdk.ListActionsArgs{
        Labels:         []string{},
        LabelQueryMode: to.Ptr(sdk.LabelQueryModeAny),
        Limit:          to.Ptr(uint32(50)),
        Offset:         to.Ptr(uint32(0)),
    }

    result, err := w.ListActions(ctx, args)
    if err != nil {
        return nil, err
    }

    log.Printf("找到 %d 个操作", result.TotalActions)
    for _, action := range result.Actions {
        log.Printf("  %s: %s - %s", *action.TxID, action.Status, action.Description)
    }

    return result, nil
}

3. 密钥管理

获取公钥

// 获取身份密钥
func getIdentityKey(ctx context.Context, w *wallet.Wallet) (string, error) {
    args := &sdk.GetPublicKeyArgs{
        IdentityKey: to.Ptr(true),
    }

    result, err := w.GetPublicKey(ctx, args)
    if err != nil {
        return "", err
    }

    return result.PublicKey, nil
}

// 获取协议的派生密钥
func getDerivedKey(
    ctx context.Context,
    w *wallet.Wallet,
    protocolID sdk.ProtocolID,
    keyID string,
    counterparty string,
) (string, error) {
    args := &sdk.GetPublicKeyArgs{
        ProtocolID:   protocolID,
        KeyID:        keyID,
        Counterparty: to.Ptr(counterparty),
    }

    result, err := w.GetPublicKey(ctx, args)
    if err != nil {
        return "", err
    }

    return result.PublicKey, nil
}

加密/解密数据

import "encoding/base64"

func encryptMessage(
    ctx context.Context,
    w *wallet.Wallet,
    plaintext string,
    recipientPubKey string,
) (string, error) {
    args := &sdk.WalletEncryptArgs{
        Plaintext:    []byte(plaintext),
        ProtocolID:   sdk.ProtocolID{2, "secure-messaging"},
        KeyID:        "msg-key",
        Counterparty: to.Ptr(recipientPubKey),
    }

    result, err := w.Encrypt(ctx, args)
    if err != nil {
        return "", err
    }

    return base64.StdEncoding.EncodeToString(result.Ciphertext), nil
}

func decryptMessage(
    ctx context.Context,
    w *wallet.Wallet,
    ciphertext string,
    senderPubKey string,
) (string, error) {
    ciphertextBytes, err := base64.StdEncoding.DecodeString(ciphertext)
    if err != nil {
        return "", err
    }

    args := &sdk.WalletDecryptArgs{
        Ciphertext:   ciphertextBytes,
        ProtocolID:   sdk.ProtocolID{2, "secure-messaging"},
        KeyID:        "msg-key",
        Counterparty: to.Ptr(senderPubKey),
    }

    result, err := w.Decrypt(ctx, args)
    if err != nil {
        return "", err
    }

    return string(result.Plaintext), nil
}

创建签名

func signData(ctx context.Context, w *wallet.Wallet, data string) (string, error) {
    args := &sdk.CreateSignatureArgs{
        Data:         []byte(data),
        ProtocolID:   sdk.ProtocolID{2, "document-signing"},
        KeyID:        "sig-key",
        Counterparty: to.Ptr("self"),
    }

    result, err := w.CreateSignature(ctx, args)
    if err != nil {
        return "", err
    }

    return base64.StdEncoding.EncodeToString(result.Signature), nil
}

4. 存储配置

SQLite存储

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

func setupSQLiteStorage(dbPath string, identityKey []byte) (*storage.Storage, error) {
    db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    opts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: identityKey,
        StorageName:        "sqlite-wallet",
    }

    return storage.NewStorage(opts)
}

MySQL存储

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

func setupMySQLStorage(dsn string, identityKey []byte) (*storage.Storage, error) {
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    opts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: identityKey,
        StorageName:        "mysql-wallet",
    }

    return storage.NewStorage(opts)
}

PostgreSQL存储

import (
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

func setupPostgresStorage(dsn string, identityKey []byte) (*storage.Storage, error) {
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    opts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: identityKey,
        StorageName:        "postgres-wallet",
    }

    return storage.NewStorage(opts)
}

5. 证书操作

获取证书(直接协议)

func acquireDirectCertificate(
    ctx context.Context,
    w *wallet.Wallet,
    certType string,
    certifier string,
) (*sdk.AcquireCertificateResult, error) {
    identityKey, _ := getIdentityKey(ctx, w)

    args := &sdk.AcquireCertificateArgs{
        AcquisitionProtocol: sdk.AcquisitionProtocolDirect,
        Type:                certType,
        Certifier:           certifier,
        SerialNumber:        []byte("cert-serial-123"),
        Subject:             identityKey,
        RevocationOutpoint:  "txid.vout",
        Fields: map[string][]byte{
            "name":  []byte("Alice Smith"),
            "email": []byte("alice@example.com"),
        },
        KeyringForSubject: map[string]string{
            // 主密钥环数据
        },
        Signature: []byte("signature-bytes"),
    }

    return w.AcquireCertificate(ctx, args)
}

获取证书(发行协议)

func requestCertificateIssuance(
    ctx context.Context,
    w *wallet.Wallet,
) (*sdk.AcquireCertificateResult, error) {
    args := &sdk.AcquireCertificateArgs{
        AcquisitionProtocol: sdk.AcquisitionProtocolIssuance,
        Type:                "https://example.com/kyc-certificate",
        Certifier:           "certifier-identity-key",
        CertifierURL:        to.Ptr("https://certifier.example.com"),
        Fields: map[string]interface{}{
            "name":      "Alice Smith",
            "birthdate": "1990-01-01",
            "country":   "US",
        },
    }

    return w.AcquireCertificate(ctx, args)
}

列出证书

func listCertificates(ctx context.Context, w *wallet.Wallet) (*sdk.ListCertificatesResult, error) {
    args := &sdk.ListCertificatesArgs{
        Certifiers: []string{"certifier-identity-key"},
        Types:      []string{"https://example.com/user-certificate"},
        Limit:      to.Ptr(uint32(50)),
        Offset:     to.Ptr(uint32(0)),
    }

    result, err := w.ListCertificates(ctx, args)
    if err != nil {
        return nil, err
    }

    log.Printf("找到 %d 个证书", result.TotalCertificates)
    for _, cert := range result.Certificates {
        log.Printf("  类型: %s, 颁发者: %s", cert.Type, cert.Certifier)
    }

    return result, nil
}

证明证书

func proveCertificate(
    ctx context.Context,
    w *wallet.Wallet,
    certificateID string,
) (*sdk.ProveCertificateResult, error) {
    args := &sdk.ProveCertificateArgs{
        CertificateID:   certificateID,
        FieldsToReveal:  []string{"name", "email"},
        Verifier:        "verifier-identity-key",
        Privileged:      to.Ptr(false),
    }

    return w.ProveCertificate(ctx, args)
}

6. 错误处理

标准错误处理

import (
    "errors"
    "github.com/bsv-blockchain/go-wallet-toolbox/pkg/defs"
)

func handleWalletError(err error) {
    if err == nil {
        return
    }

    // 检查特定错误类型
    var invalidParamErr *defs.ErrInvalidParameter
    if errors.As(err, &invalidParamErr) {
        log.Printf("参数无效: %s - %s", invalidParamErr.Parameter, invalidParamErr.Message)
        return
    }

    var internalErr *defs.ErrInternal
    if errors.As(err, &internalErr) {
        log.Printf("内部错误: %s", internalErr.Message)
        return
    }

    // 通用错误
    log.Printf("钱包错误: %v", err)
}

交易错误处理

func sendWithErrorHandling(
    ctx context.Context,
    w *wallet.Wallet,
    recipient string,
    satoshis uint64,
) (string, error) {
    txid, err := sendBSV(ctx, w, recipient, satoshis)
    if err != nil {
        handleWalletError(err)

        // 检查是否为审查操作错误
        if strings.Contains(err.Error(), "review") {
            log.Printf("交易需要审查")
            // 处理审查流程
        }

        return "", err
    }

    log.Printf("交易已发送: %s", txid)
    return txid, nil
}

7. 生产模式

钱包管理器模式

type WalletManager struct {
    wallet  *wallet.Wallet
    storage *storage.Storage
    mu      sync.RWMutex
}

func NewWalletManager(ctx context.Context, rootKey *ec.PrivateKey) (*WalletManager, error) {
    db, err := gorm.Open(sqlite.Open("wallet.db"), &gorm.Config{})
    if err != nil {
        return nil, err
    }

    storageOpts := &storage.Options{
        Db:                 db,
        StorageIdentityKey: rootKey.PubKey().Compressed(),
        StorageName:        "managed-wallet",
    }

    walletStorage, err := storage.NewStorage(storageOpts)
    if err != nil {
        return nil, err
    }

    keyDeriver := sdk.NewKeyDeriver(rootKey)
    walletServices, err := services.NewServices(ctx, &services.Options{
        Network: defs.Mainnet,
        ArcURL:  "https://arc.taal.com",
    })
    if err != nil {
        return nil, err
    }

    w, err := wallet.NewWallet(
        ctx,
        keyDeriver,
        walletStorage,
        wallet.WithServices(walletServices),
        wallet.WithNetwork(defs.Mainnet),
    )
    if err != nil {
        return nil, err
    }

    return &WalletManager{
        wallet:  w,
        storage: walletStorage,
    }, nil
}

func (wm *WalletManager) GetWallet() *wallet.Wallet {
    wm.mu.RLock()
    defer wm.mu.RUnlock()
    return wm.wallet
}

func (wm *WalletManager) Close() error {
    wm.mu.Lock()
    defer wm.mu.Unlock()

    // 清理资源
    return nil
}

重试模式

func sendWithRetry(
    ctx context.Context,
    w *wallet.Wallet,
    recipient string,
    satoshis uint64,
    maxRetries int,
) (string, error) {
    var lastErr error

    for attempt := 1; attempt <= maxRetries; attempt++ {
        txid, err := sendBSV(ctx, w, recipient, satoshis)
        if err == nil {
            return txid, nil
        }

        lastErr = err
        log.Printf("尝试 %d 失败: %v", attempt, err)

        if attempt < maxRetries {
            time.Sleep(time.Second * time.Duration(attempt))
        }
    }

    return "", fmt.Errorf("所有 %d 次重试均失败: %w", maxRetries, lastErr)
}

后台监控模式

import "github.com/bsv-blockchain/go-wallet-toolbox/pkg/monitor"

func setupMonitor(
    ctx context.Context,
    walletStorage *storage.Storage,
    walletServices *services.WalletServices,
) (*monitor.Monitor, error) {
    opts := &monitor.Options{
        Storage:  walletStorage,
        Services: walletServices,
        Network:  defs.Mainnet,
    }

    m, err := monitor.NewMonitor(ctx, opts)
    if err != nil {
        return nil, err
    }

    // 在后台启动监控
    go func() {
        if err := m.Start(ctx); err != nil {
            log.Printf("监控错误: %v", err)
        }
    }()

    return m, nil
}

🔗 额外资源


📝 常见模式总结

任务 函数 关键参数
发送BSV CreateAction() Outputs, Options
检查余额 ListOutputs() 特殊篮子
列出UTXO ListOutputs() Basket, Spendable
获取历史 ListActions() Labels, Limit
获取公钥 GetPublicKey() ProtocolID, KeyID
加密数据 Encrypt() Plaintext, Counterparty
获取证书 AcquireCertificate() Type, Certifier

记住: 始终使用context进行取消,显式处理错误,并遵循Go并发钱包访问的最佳实践!