@smartledger/bsv 5.4.1 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,79 @@ All notable changes to SmartLedger-BSV will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [5.5.0] - 2026-06-25
9
+
10
+ Minor release. Closes a front-running theft flaw in the ownership-token covenant
11
+ and generalizes the covenant core into a pluggable, multi-output state machine.
12
+
13
+ ### Security
14
+
15
+ - **`SmartContract.Token` ownership is now ECDSA-authorized.** The previous design
16
+ gated a transfer on revealing `ownerSecret` with `SHA256(ownerSecret) ==
17
+ ownerHash` — a hash-lock. The secret was exposed in the mempool on the first
18
+ spend and the spender freely chose the next owner, so a watcher could lift the
19
+ revealed secret and broadcast a competing spend redirecting the token to
20
+ themselves. Ownership is now a key: state is `HASH160(ownerPubKey)` and a
21
+ transfer requires the current owner's signature over the spend
22
+ (`OP_CHECKSIGVERIFY`), which commits via `SIGHASH_ALL` `hashOutputs` to the
23
+ exact recreated output — so altering the destination invalidates the proof.
24
+
25
+ ### Added
26
+
27
+ - **Pluggable ownership — `SmartContract.Authorizers`.** Token ownership is always
28
+ a 20-byte commitment, so the transfer plumbing is identical across schemes:
29
+ - `singleKey()` — signature over the spend (the model above).
30
+ - `multisig(m, n)` — m-of-n group ownership; the key set is committed by hashing
31
+ the canonical redeem script, revealed at spend, bound to the commitment, and
32
+ checked with `OP_CHECKMULTISIG`.
33
+ - `predicate({ commit, emit, unlockArgs })` — escape hatch for custom schemes.
34
+ - **Multi-output (N-output) tokens** — `Token.ownershipTokenMulti` /
35
+ `unlockTransferMulti` let the recreated token output sit among other outputs
36
+ (payments, change, data); the spender reveals the surrounding output bytes and
37
+ the covenant binds them into the committed `hashOutputs`.
38
+ - **`PushTx.grind` configurable nonce** — `{ field: 'nLockTime' | 'sequence' }`,
39
+ so a covenant pinning `nLockTime` for a CLTV timelock can grind the input
40
+ sequence instead. `PushTx.assertSighashAll()` guard added to token/PELS scripts.
41
+
42
+ ### Changed (breaking, `SmartContract.Token` only)
43
+
44
+ - `Token.ownershipToken(fee, owner)` — `owner` is now `HASH160(pubkey)` (use
45
+ `Token.ownerId(key)`), not `SHA256(secret)`.
46
+ - `Token.unlockTransfer(signer, newOwnerHash, spend, satoshis, lockingScript[, opts])`
47
+ — now takes the owner key and the spend (it grinds and signs), not a precomputed
48
+ preimage. The rest of the package's API is unchanged and fully compatible.
49
+
50
+ ### Notes
51
+
52
+ - Full suite **4267 passing**; `lib/` and `test/` lint clean.
53
+
54
+ ## [5.4.2] - 2026-06-25
55
+
56
+ Patch release. Dependency security maintenance — no API or behavior changes.
57
+
58
+ ### Security
59
+
60
+ - **`bn.js` `4.11.9` → `4.12.3`** — picks up the backported 4.x patch for
61
+ GHSA-378v-28hj-76wf (infinite loop via hardened hex parsing). This is the
62
+ only runtime-dependency change; the public `BN` API is unchanged. After the
63
+ bump, `npm audit --omit=dev` reports **0 vulnerabilities** in the runtime
64
+ tree.
65
+
66
+ ### Changed
67
+
68
+ - **`mocha` `^8.4.0` → `^11.7.6`** and **`nyc` `^14.1.1` → `^18.0.0`**
69
+ (dev-only). Clears the high-severity dev advisories with real upstream fixes
70
+ (cross-spawn / spawn-wrap ReDoS, the old `serialize-javascript` RCE, `nanoid`,
71
+ `uuid`). Full suite still **4256 passing**; `nyc` coverage verified.
72
+
73
+ ### Notes
74
+
75
+ - The remaining `npm audit` findings are all development-only and never reach
76
+ installers (the published tarball ships no `node_modules`; none are listed
77
+ under `dependencies`). They are either upstream-blocked (`mocha`/`nyc` are at
78
+ their latest releases but still range-pin affected transitives) or await the
79
+ deferred `standard@17` lint migration. See `SECURITY.md` for the full scope.
80
+
8
81
  ## [5.4.1] - 2026-06-25
9
82
 
10
83
  Patch release. Repairs Legal Token Protocol (LTP) right-token creation,
package/README.md CHANGED
@@ -37,9 +37,9 @@ SC.enableGenesis() // post-Genesis limits (OP_PUSH_TX need
37
37
  // Self-replicating covenant — every spend recreates the same script (value − fee).
38
38
  const lock = SC.perpetualCovenant(500)
39
39
 
40
- // Stateful ownership token (NFT) — transfer requires the owner's secret,
41
- // rewrites state, perpetuates the token code.
42
- const token = SC.ownershipToken(500, ownerHash)
40
+ // Stateful ownership token (NFT) — transfer requires the owner's ECDSA signature
41
+ // over the spend, rewrites state, perpetuates the token code.
42
+ const token = SC.ownershipToken(500, ownerHash) // ownerHash = SC.Token.ownerId(ownerKey)
43
43
 
44
44
  // Value covenant — forces spend outputs to match a specific hashOutputs.
45
45
  const vlock = SC.valueCovenant(SC.PushTx.hashOutputs(requiredOutputs))
@@ -54,7 +54,8 @@ const ok = SC.verifyScript(unlockScript, lockingScript, tx, inputIndex, satoshis
54
54
  |---|---|
55
55
  | `PushTx` | nChain WP1605 OP_PUSH_TX — `authenticator()`, `valueCovenant()`, `hashOutputs()`, `extractHashOutputs()`, `grind()` |
56
56
  | `PELS` | Perpetually Enforcing Locking Scripts — `perpetualCovenant(fee)` |
57
- | `Token` | Stateful ownership token (NFT) — `ownershipToken(fee, ownerHash)` |
57
+ | `Token` | Stateful ownership token (NFT) — `ownershipToken(fee, owner[, auth])`, `ownershipTokenMulti(owner[, auth])`, `ownerId(key)`, `unlockTransfer(...)`, `unlockTransferMulti(...)` |
58
+ | `Authorizers` | Pluggable token ownership — `singleKey()`, `multisig(m, n)`, `predicate({...})` |
58
59
  | `Locks` | Hash-lock, P2PKH, CLTV time-lock, m-of-n multisig, HTLC |
59
60
  | `CovenantHelpers` | Consensus-flag `verify()` harness, raw BIP-143 preimage, signing, fund/spend scaffolding |
60
61
 
@@ -729,11 +730,30 @@ const pels = SC.perpetualCovenant(500) // fee in satoshis deducted each hop
729
730
 
730
731
  ### Ownership Tokens (NFT) — v4.2.0 API
731
732
  ```javascript
732
- // Stateful ownership token. Owner is carried as on-chain state; transfer
733
- // requires the current owner's secret and rewrites state, perpetuating
734
- // the token code across the chain of spends.
735
- const ownerHash = bsv.crypto.Hash.sha256ripemd160(currentOwnerPubKey.toBuffer())
733
+ // Stateful ownership token. Owner is carried as on-chain state (HASH160 of the
734
+ // owner's public key); transfer requires the current owner's ECDSA SIGNATURE over
735
+ // the spend (OP_CHECKSIG) and rewrites state, perpetuating the token code across
736
+ // the chain of spends. The signature commits to the chosen next owner, so a
737
+ // mempool watcher cannot redirect a pending transfer (no hash-lock front-running).
738
+ const ownerHash = SC.Token.ownerId(currentOwnerKey) // = HASH160(pubkey)
736
739
  const token = SC.ownershipToken(500, ownerHash)
740
+ // To spend it forward to `nextOwnerHash`, the current owner signs:
741
+ // tokenInput.setScript(SC.Token.unlockTransfer(currentOwnerKey, nextOwnerHash, spendTx, sats, token))
742
+
743
+ // Pluggable ownership — the SAME covenant, owned by an m-of-n group. Ownership is
744
+ // committed as a 20-byte hash either way, so the transfer plumbing is identical.
745
+ const ms = SC.Authorizers.multisig(2, 3)
746
+ const groupToken = SC.Token.ownershipToken(500, ms.commit([pkA, pkB, pkC]), ms)
747
+ // transfer requires any 2 of the 3 keys:
748
+ // SC.Token.unlockTransfer({ keys: [pkA, pkB, pkC], signWith: [skA, skC] },
749
+ // nextOwnerHash, spendTx, sats, groupToken, { auth: ms })
750
+ // Custom schemes: SC.Authorizers.predicate({ commit, emit, unlockArgs }).
751
+
752
+ // N-output: recreate the token alongside other outputs (payments, change, data).
753
+ // The spender reveals the surrounding output bytes; the covenant binds them all.
754
+ const multi = SC.Token.ownershipTokenMulti(ownerHash)
755
+ // SC.Token.unlockTransferMulti(currentOwnerKey, nextOwnerHash, spendTx, sats, multi,
756
+ // { before: serializedOutputsBeforeToken, after: serializedOutputsAfterToken, tokenValue: le8(value) })
737
757
  ```
738
758
 
739
759
  ### End-to-end verification
package/SECURITY.md CHANGED
@@ -52,13 +52,22 @@ to remain anonymous.
52
52
  - Bugs in BIP-143 preimage handling, covenant construction, or LTP/GDAF
53
53
  signing paths.
54
54
  - Supply-chain concerns about pinned runtime dependencies
55
- (`elliptic@6.6.1`, `bn.js@4.11.9`, `bs58@4.0.1`, etc.).
55
+ (`bn.js@4.12.3`, `bs58@4.0.1`, `@noble/*`, etc.). The runtime dependency
56
+ tree carries **no known advisories** (`npm audit --omit=dev` is clean);
57
+ `elliptic` was dropped from the runtime/bundle path in 5.4.0.
56
58
 
57
59
  ## Out of Scope
58
60
 
59
61
  - Vulnerabilities in development-only dependencies (`webpack 4`, `standard 12`,
60
- `mocha 8`, etc.). These are tracked separately and addressed in the planned
61
- 3.5.0 toolchain upgrade.
62
+ `mocha`, `nyc`, `crypto-browserify`, etc.). These never reach installers — the
63
+ published tarball ships no `node_modules` and none are listed under
64
+ `dependencies`. The remaining `npm audit` findings (currently 17, all
65
+ dev-only) are either upstream-blocked — `mocha`/`nyc` are already at their
66
+ latest releases but still range-pin affected transitives (`diff`,
67
+ `serialize-javascript`, nested `js-yaml`) — or require the deferred
68
+ `standard@17` lint migration (`eslint`/`inquirer`/`tmp` chain) and the
69
+ `crypto-browserify` browser-build chain. They are accepted dev-only risk and
70
+ tracked separately.
62
71
  - Issues that require a malicious local environment (compromised Node, browser
63
72
  extension, or filesystem) to exploit.
64
73
  - Denial-of-service from intentionally malformed inputs that do **not** cross