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.
npm install @bsv/sdkimport { 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()PrivateKey, PublicKey, Hash, Signature, Entropy, Curve (secp256k1)Script, LockingScript, UnlockingScript, ScriptChunk, OP codesP2PKH (Pay-to-Public-Key-Hash), P2PK, P2SH, PushDrop for overlay protocolsTransaction, Input, Output, complete builder with signing and broadcastingSatoshisPerKilobyte, LivePolicy for network-aware fee estimationARC, WhatsOnChainBroadcaster, Teranode broadcasters; defaultChainTracker, WhatsOnChainMerklePath for merkle inclusion proofsBeef (BRC-62) for atomic transaction batches with proofsWalletInterface (BRC-100), WalletClient() factory, ProtoWallet for testingCertificate, IdentityKey, AuthModule for peer authenticationStorage interface with LocalStorageAdapter, InMemoryStorage; KVStore for distributed dataTopicBroadcaster, TopicListener, RemittanceProtocol, IdentityResolver, RegistrygenerateTOTP(), verifyTOTP() for time-based one-time passwordsimport { 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()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.
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.')
}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 }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.