<>ts-stack
Get StartedArchitecturePackagesSpecsGuides
⌘K
Reference
Home
Get StartedOverviewInstallChoose your stackKey concepts
ArchitectureOverviewStack layersBEEF (BRC-62)BRC-100 Wallet InterfaceIdentity & AuthConformance pipeline
PackagesOverviewSDK
@bsv/sdk
WalletNetworkOverlaysMessagingMiddlewareHelpers
InfrastructureOverviewmessage-box-serveroverlay-serveruhrp-server-basicuhrp-server-cloud-bucketwabwallet-infrachaintracks-server
SpecsOverviewBRC-100 Wallet InterfaceOverlay HTTPMessage-box HTTPAuthsocket (WebSocket)BRC-31 Auth HandshakeBRC-29 Peer PaymentBRC-121 / HTTP 402ARC BroadcastMerkle ServiceStorage AdapterGASP SyncUHRPAir-Gap Optical (BRC-141)
ConformanceOverviewVector catalogTS runnerContributing vectors
GuidesOverviewBuild a wallet-aware appRun an overlay nodePeer-to-peer messagingHTTP 402 payments
ReferenceOverviewBRC indexRepository health
AboutVersioningContributingDoc agentDocumentation sources
npm@bsv/sdkv2.4.1API reference (TypeDoc) ↗
Loading…
Edit this page on GitHub
© 2026 BSV Blockchain. ts-stack is open-source.
GitHubContributingVersioning

@bsv/sdk

The foundational cryptographic and transaction library for the BSV blockchain. Zero external dependencies — all cryptographic primitives have been validated by a third-party auditor. Every other library in the ts-stack builds on top of @bsv/sdk.

Provides low-level primitives (keys, signatures, hashing), script construction and execution, transaction creation and signing, and integration interfaces for wallets and overlay networks.

Install

bash
npm install @bsv/sdk

Quick start

typescript
import { PrivateKey, P2PKH, Transaction } from '@bsv/sdk'

const privKey = PrivateKey.fromWif('L5EY1SbTvvPNSdCYQe1EJHfXCBBT4PmnF6CDbzCm9iifZptUvDGB')
const sourceTransaction = Transaction.fromHex('0200000001...') // Previous tx hex
const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX'

const tx = new Transaction(
  1,
  [
    {
      sourceTransaction,
      sourceOutputIndex: 0,
      unlockingScriptTemplate: new P2PKH().unlock(privKey)
    }
  ],
  [
    {
      lockingScript: new P2PKH().lock(recipientAddress),
      satoshis: 5000
    },
    {
      lockingScript: new P2PKH().lock(privKey.toAddress()),
      change: true
    }
  ]
)

await tx.fee()
await tx.sign()
const broadcast = await tx.broadcast()

What it provides

  • Cryptographic primitives — PrivateKey, PublicKey, Hash, Signature, Entropy, Curve (secp256k1)
  • Script building — Script, LockingScript, UnlockingScript, ScriptChunk, OP codes
  • Script templates — P2PKH (Pay-to-Public-Key-Hash), P2PK, P2SH, PushDrop for overlay protocols
  • Transaction building — Transaction, Input, Output, complete builder with signing and broadcasting
  • Fee models — SatoshisPerKilobyte, LivePolicy for network-aware fee estimation
  • Network integration — ARC, WhatsOnChainBroadcaster, Teranode broadcasters; defaultChainTracker, WhatsOnChain
  • SPV verification — MerklePath for merkle inclusion proofs
  • BEEF envelopes — Beef (BRC-62) for atomic transaction batches with proofs
  • Message signing — BRC-18 signed messages
  • Wallet interface — WalletInterface (BRC-100), WalletClient() factory, ProtoWallet for testing
  • Auth & identity — Certificate, IdentityKey, AuthModule for peer authentication
  • Storage & KV — Storage interface with LocalStorageAdapter, InMemoryStorage; KVStore for distributed data
  • Overlay integration — TopicBroadcaster, TopicListener, RemittanceProtocol, IdentityResolver, Registry
  • 2FA — generateTOTP(), verifyTOTP() for time-based one-time passwords

Common patterns

Build a P2PKH transaction

typescript
import { PrivateKey, P2PKH, Transaction } from '@bsv/sdk'

const privKey = PrivateKey.fromWif('L5EY1SbTvvPNSdCYQe1EJHfXCBBT4PmnF6CDbzCm9iifZptUvDGB')
const sourceTransaction = Transaction.fromHex('0200000001...')
const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX'

const tx = new Transaction(
  1,
  [
    {
      sourceTransaction,
      sourceOutputIndex: 0,
      unlockingScriptTemplate: new P2PKH().unlock(privKey)
    }
  ],
  [
    {
      lockingScript: new P2PKH().lock(recipientAddress),
      satoshis: 5000
    },
    {
      lockingScript: new P2PKH().lock(privKey.toAddress()),
      change: true
    }
  ]
)

await tx.fee()
await tx.sign()

Connect to a BRC-100 wallet

typescript
import { P2PKH, WalletClient } from '@bsv/sdk'

const wallet = new WalletClient('auto', 'example.com')
const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX'
const lockingScript = new P2PKH().lock(recipientAddress).toHex()

const { publicKey } = await wallet.getPublicKey({
  identityKey: true
})

const action = await wallet.createAction({
  description: 'Create payment',
  outputs: [
    {
      lockingScript,
      satoshis: 1000,
      outputDescription: 'Payment output'
    }
  ]
})

console.log(publicKey, action.txid)

WalletClient implements the BRC-100 method surface. It discovers a wallet substrate such as BSV Desktop over localhost or BSV Browser over a postMessage bridge.

CreateActionResult can carry AtomicBEEF as either a historical number[] or a binary Wallet Wire Uint8Array. BRC-29 remittance accepts both and emits a portable number[] settlement artifact for JSON-safe transport.

For advanced postMessage integrations, XDM defaults to the wildcard target origin so public apps, mobile webviews, and opaque origins can reach an embedded wallet. Every response must still come from the current parent window and match the invocation's random request ID. When the wallet parent has a stable known origin, pass that exact origin to new XDM('https://wallet.example') to require it on both outbound and inbound messages. This transport choice is independent of CORS and of any CSP applied to an app's documents.

Verify SPV with merkle proof

typescript
import { Transaction, WhatsOnChain } from '@bsv/sdk'

const beefHex = [
  '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5b',
  'c70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395ef',
  'd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f',
  '44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d616',
  '07f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f',
  '01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd',
  '7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655',
  'e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa',
  '3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710',
  'd9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76',
  'ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001',
  '000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47',
  '304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9a',
  'a2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd237',
  '8bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d4580',
  '3dbcf0c87dd3c71efbc288ac0000000000'
].join('')

const tx = Transaction.fromHexBEEF(beefHex)
const chainTracker = new WhatsOnChain()

if (await tx.verify(chainTracker)) {
  console.log('This transaction is on chain, proven with SPV.')
}

Encode data on-chain with PushDrop

typescript
import { PushDrop, Utils, WalletClient } from '@bsv/sdk'

const wallet = new WalletClient('auto', 'example.com')
const pushDrop = new PushDrop(wallet)

const lockingScript = await pushDrop.lock(
  [
    Utils.toArray('myAssetId', 'utf8'),
    Utils.toArray('100', 'utf8'),
    Utils.toArray(JSON.stringify({ name: 'MyToken' }), 'utf8')
  ],
  [2, 'my app token'],
  'asset-1',
  'self',
  true,
  false
)

const output = { lockingScript: lockingScript.toHex(), satoshis: 1 }

Key concepts

  • Private Key — 256-bit value from which all wallet operations derive. Never exposed in network traffic.
  • Public Key — Elliptic curve point derived from private key; used for address generation and signature verification.
  • Script — Combination of operation codes and data that define spending conditions. Locking scripts constrain outputs; unlocking scripts unlock them.
  • Transaction — Atomic unit of blockchain state change. Inputs reference previous outputs (UTXOs); outputs create new UTXOs.
  • UTXO — Unspent Transaction Output; identified by (txid, outputIndex). Spending requires a valid unlocking script.
  • Signature — ECDSA signature with sighash byte indicating which transaction fields are committed to.
  • Merkle Proof — Proof of inclusion in a block; enables SPV without downloading full blocks.
  • BEEF — BRC-62 envelope; atomic bundle of transactions with merkle proofs for offline verification.
  • Wallet Interface (BRC-100) — Standardized interface for wallet RPC between apps and wallet services. Abstracts away key management.
  • Overlay — Second-layer protocol using on-chain anchors (PushDrop) to build services without blockchain modifications.

When to use this

  • You're building any BSV application that needs to create, sign, or verify transactions
  • You need to work with Bitcoin Script or transaction primitives
  • You're implementing key management or cryptographic operations
  • You want to build SPV-based light clients
  • You need to integrate with overlay protocols using PushDrop

When NOT to use this

  • Use @bsv/wallet-toolbox instead if you need full wallet functionality with persistent storage and signing management
  • Use @bsv/btms if you're building token issuance/transfer (it abstracts the Script encoding)
  • Use @bsv/wallet-relay if you need mobile-to-desktop wallet pairing

Spec conformance

  • BRC-18 — Signed messages
  • BRC-29 — Bitcoin Envelope (UTXO-addressed messages)
  • BRC-42, BRC-43 — Key derivation protocols
  • BRC-62 — BEEF (transaction envelope format)
  • BRC-100 — Wallet interface standard
  • SPV — Full merkle proof verification support
  • Bitcoin Script — Full consensus-rule-compliant interpreter

Common pitfalls

Sighash commit mismatch — Unlocking script hash commits only to parts of the transaction. If you modify tx after signing, signature becomes invalid. Always sign last.

Fee estimation timing — tx.fee() may vary if mempool conditions change. Estimate early and buffer for volatility, or use live fee trackers.

UTXO reuse across parallel transactions — If two transactions reference the same UTXO, only one will confirm. Wallet implementations must track pending outputs.

Script evaluation order — Unlocking script is evaluated first, then locking script. Stack must be left with true atop for success.

Broadcast endpoint differences — ARC, WhatsOnChain, Teranode have different response formats and rate limits. Implement retry logic and fallback chains.

Related packages

  • @bsv/wallet-toolbox — Complete wallet implementation with storage and signing
  • @bsv/btms — Token issuance and transfer
  • @bsv/wallet-relay — Mobile wallet pairing

Reference

  • API reference (TypeDoc)
  • Source on GitHub
  • npm