Skip to content

fix(wallet-toolbox): restore inline locking scripts on funding outputs read with noScript - #1139

Draft
GenericCPU wants to merge 4 commits into
bsv-blockchain:mainfrom
GenericCPU:fix/wallet-toolbox-funding-output-script
Draft

GenericCPU wants to merge 4 commits into
bsv-blockchain:mainfrom
GenericCPU:fix/wallet-toolbox-funding-output-script

Conversation

@GenericCPU

@GenericCPU GenericCPU commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Program and scope

  • Tracker or issue: fix(wallet-toolbox): findings from running the toolbox as a production IndexedDB wallet #1136 (finding 2)
  • Program gate(s) advanced: none; standalone defect fix
  • Why this change is needed: StorageIdb.allocateChangeInput and availableManagedChange read candidates with noScript: true. validateOutputScript only reloads a script offloaded into the raw transaction, so a script stored inline on the output row stayed cleared, and funding reached the signer without a locking script. Adds an internal storage/methods/restoreOutputScript helper (raw-transaction slice first, then a reread of the row) and uses it in allocateChangeInput and makeFundingResult.
  • Explicitly out of scope: Which output is selected, the noScript scans themselves, and offloaded-script handling are unchanged. No public API change: the helper lives in storage/methods, which the package does not export. The other findings in the issue each have their own pull request or are proposals.
  • Exact head SHA reviewed: 517b4b0c989abe1cc95a56f4bdd0595656048000

Impact

  • No public package source or manifest changed
  • Public package source or manifest changed; affected packages are listed below
  • Infrastructure source, dependency, image, or deployment configuration changed
  • Public API, exports, types, runtime targets, or browser/mobile behavior changed
  • Security-sensitive boundary changed
  • Documentation or examples changed

Affected packages/services and intended patch versions (publication occurs only
through the release workflow after approval): @bsv/wallet-toolbox patch.

Verification

  • Local commands and results (Node 24.22.0, pnpm, from the repository root at 517b4b0c989abe1cc95a56f4bdd0595656048000):
    • pnpm --filter @bsv/wallet-toolbox exec jest --watchman=false src/storage/__test/allocateChangeInputScript.test.ts: 5 passed, 5 total; actionBatch.test.ts (which runs makeFundingResult) 61 passed. New test: allocateChangeInput on SQLite and IndexedDB over each row shape validateOutputScript cannot fill (inline scriptOffset: 0; restored or synced without txid/scriptOffset/scriptLength; offloaded with no stored raw transaction), plus a guard that offloaded scripts in a stored raw transaction still rebuild from it. Without the source change it fails all three shape cases on IndexedDB (3 failed, 2 passed).
    • cd packages/wallet/wallet-toolbox && pnpm exec tsc --noEmit -p tsconfig.json: exit 0
    • pnpm exec oxlint <changed files>: exit 0, no warnings
    • pnpm exec prettier --check <changed files>: clean on every changed hunk; StorageIdb.ts reports one pre-existing warning (the certifiers filter line) that main also has, left untouched to keep this diff to the fix
  • Hosted CI run: pending on this head
  • Conformance evidence: not applicable
  • Coverage delta: new regression test only
  • Lint/typecheck delta: none
  • Browser/mobile/packed-consumer evidence: the same fix runs in HandCash Desktop (Electron) and HandCash Mobile (Android WebView) on IndexedDB storage; see the reference links in the issue
  • Performance or bundle-size delta: none expected
  • I self-reviewed the complete diff for correctness, security,
    compatibility, public API, artifacts, dependencies, docs, and operations
  • All applicable checks are terminal and successful on the exact head; any
    scope-based skip is expected and validated by the merge gate

Security and dependencies

  • No dependency or lockfile change
  • Changelog, runtime relevance, peer compatibility, transitive graph, and
    audit results were reviewed
  • CodeQL/negative tests cover any changed trust boundary
  • The exact-head CodeQL analysis has no new alert
  • The exact-head repository quality gate reports zero new Sonar findings
    (including accepted or false-positive issue states) and zero unreviewed hotspots;
    Sonar's aggregate Quality Gate passed verdict alone is not merge evidence
  • No new override, advisory dismissal, quality suppression, or skipped test
  • Any temporary exception is registered with owner, evidence, review date,
    and removal condition
  • Workflow permissions and lifecycle-script behavior remain least privilege

Release and operations

  • No npm publication was performed from a workstation or from this PR
  • Required npm patch bumps are included or intentionally deferred by the
    controlling program (deferred to the release workflow)
  • Image/SBOM/provenance/deployment/rollback impact is documented
  • Documentation, changelog, migration, and operational guidance are current

Completion evidence

  • The linked tracker is updated only for work fully proved by merged code,
    passing checks, resolved alerts, measurements, or an approved exception
  • Review conversations are resolved
  • Documentation, changelog, migration notes, release notes, and operator
    guidance are current or concretely not applicable
  • No pending, failed, stale, cancelled, or unexpectedly skipped check is
    being handed to another contributor as "complete"
  • One qualified maintainer approval is sufficient; no last-pusher
    restriction is assumed

…en from a noScript scan

Change candidates are read with noScript: true, which clears every locking
script. validateOutputScript reloads only a script offloaded into the raw
transaction, so an output whose script is stored inline on its row left
StorageIdb.allocateChangeInput, and makeFundingResult for action batches,
with no locking script. The signer then received a funding input it cannot
sign.

Add StorageProvider.restoreOutputScript, which falls back to rereading the
row, and use it in both funding paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
GenericCPU and others added 3 commits October 17, 2026 00:12
Run allocateChangeInput over every row shape validateOutputScript cannot fill:
an inline script, a row restored or synced without txid/scriptOffset/
scriptLength, and an offloaded script whose raw transaction storage no longer
holds. Guard that a script offloaded into a stored raw transaction is still
rebuilt from it.

Co-authored-by: Cursor <cursoragent@cursor.com>
…rageProvider API

Move the helper into storage/methods, which the package does not export, so the
fix adds no public method a subclass could collide with.

Co-authored-by: Cursor <cursoragent@cursor.com>
… funding result

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant