You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Keystore transfer via prepareTxEnhanced on BTC/BCH/LTC/DOGE/DASH; Bitcoin Ledger
npm coinselect/accumulative
Per-chain buildTx / Utils.buildTx
Legacy prepareTx / buildTx; BCH/LTC/DOGE/DASH Ledger still call prepareTx
Bitcoin was cleaned up first (prepareTxEnhanced end-to-end). Other UTXO chains got enhanced bolted on but kept the old coinselect path for compatibility. Dead leftover on bitcoin: coinselect in package.json + src/modules.d.ts (no imports).
Related: monorepo pin bump #1745 (3.1.12 → 3.1.13) is hygiene only — 3.1.13 only changes split.js; we never call split, only accumulative (identical across those versions).
coinselect vs xchain-utxo (short)
coinselect: output-list API, P2PKH-ish size estimates, default entry is blackjack→accumulative; we only import accumulative.js.
Fee/input counts can differ at the margin for the same UTXO set because size models differ.
Full write-up lived in internal review notes; this issue is the actionable follow-up.
Goal
One selection path for all UTXO chains: selectUtxosForTransaction / prepareTxEnhanced only. Remove npm coinselect from the monorepo when nothing imports it.
Current call graph (as of 2026-08)
Chain
Keystore transfer
Ledger transfer
Still imports coinselect?
Bitcoin
prepareTxEnhanced
prepareTxEnhanced
Dep only (unused)
BCH
prepareTxEnhanced
prepareTx → coinselect
Yes
LTC
prepareTxEnhanced
prepareTx → coinselect
Yes
DOGE
prepareTxEnhanced
prepareTx → coinselect
Yes
DASH
prepareTxEnhanced
prepareTx → Utils.buildTx → coinselect
Yes
ZEC
own / utxo base (no coinselect)
—
No
Implementation plan
Work one chain at a time (Ledger is the risky surface). Prefer PR order: LTC → DOGE → BCH → DASH → bitcoin cleanup → monorepo delete.
Document in each remaining package that prepareTx / buildTx are deprecated in favor of prepareTxEnhanced (already true in several places — keep consistent).
Phase 1 — Point Ledger at enhanced (per chain)
For each of LTC, DOGE, BCH, DASH:
Change ClientLedger.transfer (and transferMax if present) to call prepareTxEnhanced (or the same path keystore uses), not prepareTx.
Confirm Ledger signing still receives the right shape:
PSBT / raw tx encoding
input list / txHex / witnessUtxo as required by @ledgerhq/hw-app-btc (or chain-specific app)
Drop "coinselect" from that package’s package.json.
Patch changeset; run package unit tests + any existing e2e.
Memo gotcha: LTC/DOGE historically passed { script, value: 0 }into coinselect so fee sizing included OP_RETURN. Enhanced path uses extraOutputs / post-selection memo — verify fee and dust behavior with memo still match expectations.
Size model gotcha: enhanced uses shared P2WPKH-ish constants from xchain-utxo. Expect small fee differences vs coinselect’s P2PKH-ish estimates; document if product needs chain-specific constants later (esp. BCH/DASH non-segwit scripts).
Phase 3 — Monorepo cleanup
yarn / lockfile: no remaining coinselect resolutions.
Grep clean: no coinselect under packages/**/src.
Close or supersede any Dependabot coinselect PRs as obsolete.
Context
UTXO selection currently exists in two stacks:
@xchainjs/xchain-utxostrategiesUtxoSelector(BnB, SingleRandomDraw, Accumulative, LargestFirst, SmallFirst)transferviaprepareTxEnhancedon BTC/BCH/LTC/DOGE/DASH; Bitcoin Ledgercoinselect/accumulativebuildTx/Utils.buildTxprepareTx/buildTx; BCH/LTC/DOGE/DASH Ledger still callprepareTxBitcoin was cleaned up first (
prepareTxEnhancedend-to-end). Other UTXO chains got enhanced bolted on but kept the oldcoinselectpath for compatibility. Dead leftover on bitcoin:coinselectinpackage.json+src/modules.d.ts(no imports).Related: monorepo pin bump #1745 (
3.1.12→3.1.13) is hygiene only — 3.1.13 only changessplit.js; we never callsplit, onlyaccumulative(identical across those versions).coinselect vs xchain-utxo (short)
accumulative.js.extraOutputs+ preferences; multi-strategy tournament; fixed P2WPKH-ish vbyte constants (68/31/10); typedUtxoError.Goal
One selection path for all UTXO chains:
selectUtxosForTransaction/prepareTxEnhancedonly. Remove npmcoinselectfrom the monorepo when nothing imports it.Current call graph (as of 2026-08)
transfertransfercoinselect?prepareTxEnhancedprepareTxEnhancedprepareTxEnhancedprepareTx→ coinselectprepareTxEnhancedprepareTx→ coinselectprepareTxEnhancedprepareTx→ coinselectprepareTxEnhancedprepareTx→ Utils.buildTx → coinselectImplementation plan
Work one chain at a time (Ledger is the risky surface). Prefer PR order: LTC → DOGE → BCH → DASH → bitcoin cleanup → monorepo delete.
Phase 0 — Housekeeping (optional small PR)
"coinselect"dependency andpackages/xchain-bitcoin/src/modules.d.ts(coinselect shim only). Patch changeset.prepareTx/buildTxare deprecated in favor ofprepareTxEnhanced(already true in several places — keep consistent).Phase 1 — Point Ledger at enhanced (per chain)
For each of LTC, DOGE, BCH, DASH:
ClientLedger.transfer(andtransferMaxif present) to callprepareTxEnhanced(or the same path keystore uses), notprepareTx.txHex/witnessUtxoas required by@ledgerhq/hw-app-btc(or chain-specific app)prepareTxtemporarily as a thin deprecated wrapper or route it to enhanced for external callers (prefer one implementation).Phase 2 — Delete legacy coinselect builders (per chain)
After Ledger + keystore both use enhanced:
import accumulative from 'coinselect/accumulative.js'.buildTxbody that only existed for coinselect (or reduce to call enhanced internals).modules.d.tscoinselect module declaration."coinselect"from that package’spackage.json.Memo gotcha: LTC/DOGE historically passed
{ script, value: 0 }into coinselect so fee sizing included OP_RETURN. Enhanced path usesextraOutputs/ post-selection memo — verify fee and dust behavior with memo still match expectations.Size model gotcha: enhanced uses shared P2WPKH-ish constants from
xchain-utxo. Expect small fee differences vs coinselect’s P2PKH-ish estimates; document if product needs chain-specific constants later (esp. BCH/DASH non-segwit scripts).Phase 3 — Monorepo cleanup
yarn/ lockfile: no remainingcoinselectresolutions.coinselectunderpackages/**/src.Phase 4 — Optional hardening (separate issues OK)
xchain-utxoto avoid drift across chains.Acceptance criteria
coinselect.xchain-utxoselection only.prepareTxeither removed or delegated to enhanced (no second algorithm).Out of scope
References
packages/xchain-utxo/src/utxo-selector.ts,packages/xchain-utxo/src/strategies/*coinselect/accumulative.jsimports in BCH/LTC/DOGE/DASHpackages/xchain-bitcoin/src/client.ts(buildTxEnhanced/prepareTxEnhanced)