@smartledger/bsv
v9.43.0
Published
Bitcoin SV library with an interpreter-verified script engine: OP_PUSH_TX covenants, BIP-143 preimage tooling, and consensus flags that match what miners actually enforce. Also ships DID:web / W3C VC-JWT credentials and the Legal Token Protocol.
Downloads
7,169
Maintainers
Readme
SmartLedger-BSV
Bitcoin SV library with an interpreter-verified script engine.
Its defaults describe BSV as the network actually runs it. verify() with no
flags means current mainnet consensus, not "no rules"; the interpreter is
measured against the reference node's own vectors (1483/1483, zero false
accepts) rather than the Bitcoin Core vectors inherited from the upstream fork;
and all secp256k1 work runs on the audited, constant-time
@noble suite with elliptic
removed.
9.x will not break your code until at least 2027-09-01. Patch and minor releases only. This library published six majors in the 82 days before that commitment; STABILITY.md explains what changed and how correctness fixes now ship without breaking callers.
npm install @smartledger/bsvCovenants that actually enforce
A covenant constrains the transaction that spends it. The script has no opcode
for reading its own spend, so OP_PUSH_TX fixes the private key a = 1 and
ephemeral key k = 1, collapsing ECDSA to s = (z + Gx) mod n — plain
arithmetic the script can do on a BIP-143 preimage sitting on the stack.
OP_CHECKSIG against the generator G then proves that data really is this
transaction's preimage. No trusted signer is involved.
const bsv = require('@smartledger/bsv')
const { Script, Transaction, crypto } = bsv
const P = bsv.SmartContract.PushTx
// Commit to the only outputs this coin may ever be spent to.
const dest = Script.fromASM('OP_FALSE OP_RETURN 636f76656e616e74')
const allowed = [new Transaction.Output({ script: dest, satoshis: 99000 })]
const lock = P.valueCovenant(P.hashOutputs(allowed)) // ~419 bytes
// Spend it. `grind` nudges nLockTime until the script-derived signature is
// canonical (low-S); the cost falls on the spender, not on script size.
const g = P.grind(spendingTx, 0, lock, 100000)
const unlock = new Script().add(g.preimage) // the preimage IS the unlock
new Script.Interpreter().verify(unlock, lock, spendingTx, 0, undefined, new crypto.BN(100000))
// => true, and false for any transaction that redirects the outputsTo bind only the output at the spending input's own index — a marketplace trade where the
counterparty supplies the surrounding outputs — use valueCovenantSingle, which pins the
SIGHASH_SINGLE flag along with the output:
const lock = P.valueCovenantSingle(allowed[0]) // SIGHASH_SINGLE|FORKID, ~428 bytes
const g = P.grind(spendingTx, 0, lock, 100000, { sighashType: P.SIGHASH_SINGLE_FORKID })It constrains one output and leaves every other output free — that is what the flag means,
and it is the wrong tool for binding where value goes. valueCovenant above commits to all of
them.
Every locking script in bsv.SmartContract ships with both a must-accept and a
must-reject test. Higher-level pieces built on the same core:
const SC = bsv.SmartContract
SC.perpetualCovenant(500) // every spend recreates the same script (value − fee)
SC.ownershipToken(500, ownerHash) // NFT; transfer needs the owner's signature over the spend
SC.policy({ /* ... */ }) // declarative front-end over OP_PUSH_TXThe one thing that will bite you
Flags and limits are separate mechanisms. The era bits (SCRIPT_GENESIS,
SCRIPT_UTXO_AFTER_GENESIS, and the Chronicle pair) are what the interpreter
derives its element-size, script-size, opcode-count and script-number caps from.
Hand-assemble a flag word out of named constants — the idiom every pre-Genesis tutorial teaches — and you get the feature opcodes you asked for while silently keeping the 2019 caps. The script runs, so nothing looks wrong until a 586-byte preimage is rejected against a 520-byte limit and the error blames the push instead of the flags.
// Correct — resolves to current mainnet:
interp.verify(unlock, lock, tx, 0, undefined, satoshisBN)
interp.verify(unlock, lock, tx, 0, Script.Interpreter.mainnetFlags(), satoshisBN)
// Silently pre-Genesis, and the reason your covenant "doesn't work":
interp.verify(unlock, lock, tx, 0, SCRIPT_ENABLE_MONOLITH_OPCODES | ..., satoshisBN)Since 9.1.0 a failure caused this way sets interp.eraHint and prints one
explanatory warning per process. Deliberate pre-Genesis testing is legitimate
and stays silent unless it trips an era-derived limit; set
Interpreter.eraDiagnostics = false or BSV_NO_ERA_HINT=1 to turn the notice
off entirely.
Core Bitcoin API
Drop-in compatible with the classic bsv 1.5.6 surface.
const { PrivateKey, Transaction, Script, Address, HDPrivateKey } = require('@smartledger/bsv')
const key = PrivateKey.fromRandom()
const tx = new Transaction()
.from(utxos)
.to(address, 50000)
.change(key.toAddress())
.sign(key)Custom locking scripts need the subscript and amount passed explicitly — BIP-143
signs both, and tx.sign() only knows P2PKH:
const sig = Transaction.sighash.sign(
tx, privateKey, sighashType, inputIndex, lockingScript, new crypto.BN(satoshis)
)
const push = Buffer.concat([sig.toDER(), Buffer.from([sighashType])]) // flag byte requiredAlso included: Block, MerkleBlock, SPV, Mnemonic (BIP-39), ECIES,
Message, Shamir, Ordinals, NotaryHash (BRC-220).
Credentials and legal tokens
Standards-based issuance and verification, ES256/ES256K, with on-chain BSV anchoring. These are substantial subsystems; each has its own guide.
const { createDID, createEmailCredential, verifyCredential } = require('@smartledger/bsv')| Area | Entry point | Guide |
|---|---|---|
| DID:web + VC-JWT | bsv.DIDWeb, bsv.VcJwt | docs/technical/GDAF_DEVELOPER_INTERFACE.md |
| Revocation (StatusList2021) | bsv.StatusList | docs/MODULE_REFERENCE_COMPLETE.md |
| Legal Token Protocol | bsv.LTP | docs/advanced/LEGAL_TOKEN_PROTOCOL.md |
| Attestation (GDAF) | bsv.GDAF | docs/technical/GDAF_IMPLEMENTATION_COMPLETE.md |
| Blockchain anchoring | bsv.Anchor | docs/MODULE_REFERENCE_COMPLETE.md |
A CLI covers the common credential workflow end to end:
npx smartledger-bsv didweb:init --domain example.com
npx smartledger-bsv vc:issue --subject did:web:example.com:alice --type EmailCredential
npx smartledger-bsv vc:verify --token ./credential.jwtLoading options
Node and bundlers get tree-shakeable subpaths; browsers can take a single file from a CDN. Importing the package root pulls in every subsystem, so prefer a subpath when you only need part of it:
const Script = require('@smartledger/bsv/lib/script') // 24 modules
const bsv = require('@smartledger/bsv') // 128 modulesCore Modules
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| bsv.min.js | 1084KB | Core BSV + SmartContract | unpkg.com/@smartledger/[email protected]/bsv.min.js |
| bsv.bundle.js | 1084KB | Everything in one file | unpkg.com/@smartledger/[email protected]/bsv.bundle.js |
W3C Verifiable Credentials
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| 🟢 bsv-didweb.min.js | 166KB | DID:web generation | unpkg.com/@smartledger/[email protected]/bsv-didweb.min.js |
| 🟢 bsv-vcjwt.min.js | 166KB | VC-JWT issue/verify | unpkg.com/@smartledger/[email protected]/bsv-vcjwt.min.js |
| 🟢 bsv-statuslist.min.js | 256KB | StatusList2021 revocation | unpkg.com/@smartledger/[email protected]/bsv-statuslist.min.js |
| 🟢 bsv-anchor.min.js | 164KB | BSV anchoring (hash-only) | unpkg.com/@smartledger/[email protected]/bsv-anchor.min.js |
Smart Contract & Development
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| bsv-smartcontract.min.js | 144KB | Complete covenant framework | unpkg.com/@smartledger/[email protected]/bsv-smartcontract.min.js |
| bsv-covenant.min.js | 35KB | Covenant operations | unpkg.com/@smartledger/[email protected]/bsv-covenant.min.js |
| bsv-script-helper.min.js | 33KB | Custom script tools | unpkg.com/@smartledger/[email protected]/bsv-script-helper.min.js |
| bsv-security.min.js | 32KB | Security enhancements | unpkg.com/@smartledger/[email protected]/bsv-security.min.js |
Legal & Compliance
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| bsv-ltp.min.js | 550KB | Legal Token Protocol | unpkg.com/@smartledger/[email protected]/bsv-ltp.min.js |
| bsv-gdaf.min.js | 1084KB | Digital Identity & Attestation | unpkg.com/@smartledger/[email protected]/bsv-gdaf.min.js |
Advanced Cryptography
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| bsv-shamir.min.js | 177KB | Threshold Cryptography | unpkg.com/@smartledger/[email protected]/bsv-shamir.min.js |
Utilities
| Module | Size | Use Case | CDN |
|--------|------|----------|-----|
| bsv-ecies.min.js | 139KB | Encryption | unpkg.com/@smartledger/[email protected]/bsv-ecies.min.js |
| bsv-message.min.js | 37KB | Message signing | unpkg.com/@smartledger/[email protected]/bsv-message.min.js |
| bsv-mnemonic.min.js | 322KB | HD wallets | unpkg.com/@smartledger/[email protected]/bsv-mnemonic.min.js |
<script src="https://unpkg.com/@smartledger/[email protected]/bsv.min.js"></script>
<script>
const key = bsv.PrivateKey.fromRandom()
</script>Pin the version in CDN URLs. A floating @latest will move under you even
within 9.x.
Documentation
| | |
|---|---|
| docs/RELIED-UPON-PROPERTIES.md | read this first if you are building on the library — what is canonical, what is malleable, what we refuse, and the return conventions that differ between verification functions |
| STABILITY.md | release policy, deprecation process, what's covered |
| docs/RELEASE-10.0.0.md | every breaking change the next major has promised, and the notice each one has already shipped |
| docs/advanced/ADVANCED_COVENANT_DEVELOPMENT.md | covenant patterns beyond the basics |
| docs/advanced/CUSTOM_SCRIPT_DEVELOPMENT.md | signing arbitrary locking scripts |
| docs/preimage.md | BIP-143 preimage field layout |
| docs/pushtx-key-insights.md | the nChain OP_PUSH_TX construction and its security claims |
| docs/api/SCRIPTS.md | script API reference |
| docs/migration/FROM_BSV_1_5_6.md | migrating from classic bsv |
| SECURITY.md | reporting vulnerabilities |
| CHANGELOG.md | release history |
Verifying this library yourself
Consensus behavior is pinned by vectors generated against the reference implementation, not by this library's own opinion:
npm test # unit + integration
npm run conformance # 452 cases against the reference corpus
npm run vectors:sv # SV consensus vector reportContributing
Issues and pull requests: https://github.com/codenlighten/smartledger-bsv
Two rules matter more than the rest. Consensus changes need a conformance vector in the same commit. Removing or breaking a public API needs a deprecation notice that has shipped in an earlier minor — see STABILITY.md.
License
MIT
SmartLedger-BSV v9.43.0
