Skip to content

Initialize ECC library eagerly so Taproot sends work#450

Open
j0ntz wants to merge 1 commit into
masterfrom
jon/fix/taproot-initecclib-eager
Open

Initialize ECC library eagerly so Taproot sends work#450
j0ntz wants to merge 1 commit into
masterfrom
jon/fix/taproot-initecclib-eager

Conversation

@j0ntz

@j0ntz j0ntz commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

initEccLib(secp256k1) was only called lazily, inside getECPair(). But Taproot (p2tr) address handling in addressToScriptPubkeyguessAddressTypeFromAddresspayments.p2tr also requires the ECC library, and that path can run before any ECPair/signing operation — most notably when makeSpend converts a Taproot recipient address to a scriptPubkey.

As a result, sending to a bc1p… (Taproot / bech32m) address failed: payments.p2tr threw "No ECC Library provided. You must call initEccLib()", which guessAddressTypeFromAddress swallowed, surfacing as unable to convert address … to script pubkey. SegWit v0 (bc1q…) sends were unaffected because they don't need ECC for address conversion.

Fix: initialize the ECC library once at module load (using the already-present @bitcoinerlab/secp256k1 dep), so Taproot address handling works regardless of call order. The existing lazy init in getECPair() is left in place (idempotent).

How it was found

Integrating the Breez SDK - Spark for Bitcoin Lightning sends in edge-react-gui (EdgeApp/edge-react-gui#6017). Spark deposit addresses are Taproot (bc1p…), so funding a Spark wallet from an Edge BTC wallet requires sending to one — which failed until this fix.

Testing

Verified on iOS: with this change, makeSpend to a Taproot address succeeds and broadcasts a valid P2TR-output transaction (confirmed on mainnet), which the prior code could not do. Isolated repro: payments.p2tr({ address: 'bc1p…', network }) throws without initEccLib, succeeds with it.

Asana: https://app.asana.com/0/1215088146871429/1215168882923123

🤖 Generated with Claude Code


Note

Low Risk
Single startup init using an existing dependency; no auth or transaction-logic changes beyond enabling p2tr address parsing.

Overview
Fixes Taproot (bc1p…) sends by calling initEccLib with @bitcoinerlab/secp256k1 when keymanager loads, instead of relying only on lazy init inside getECPair().

Spend building can run addressToScriptPubkey / guessAddressTypeFromAddress / payments.p2tr before any signing path runs; without ECC registered, that failed with No ECC Library provided and surfaced as unable to convert the address to script pubkey. SegWit v0 (bc1q…) was unaffected. Lazy getECPair() init is unchanged and remains idempotent.

Reviewed by Cursor Bugbot for commit c1717cb. Bugbot is set up for automated code reviews on this repo. Configure here.

`initEccLib(secp256k1)` was only called lazily inside `getECPair()`, but
Taproot (p2tr) address parsing in `addressToScriptPubkey` (via
`payments.p2tr`) needs the ECC library too — and that path can run before
any ECPair/signing operation, e.g. when `makeSpend` converts a Taproot
recipient address to a scriptPubkey. As a result, sending to a `bc1p…`
address failed with "No ECC Library provided". Segwit v0 (`bc1q…`) sends
were unaffected because they don't require ECC for address conversion.

Initialize the ECC library once at module load so Taproot address handling
works regardless of call order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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