Skip to content

Bitcoin UTXO management redesign#3601

Draft
TaprootFreak wants to merge 1 commit intodevelopfrom
feature/bitcoin-utxo-management
Draft

Bitcoin UTXO management redesign#3601
TaprootFreak wants to merge 1 commit intodevelopfrom
feature/bitcoin-utxo-management

Conversation

@TaprootFreak
Copy link
Copy Markdown
Collaborator

Summary

Replaces the two-node Bitcoin architecture (separate input/output wallets) with a single descriptor wallet where addresses are never reused. Every deposit gets a unique address, every transaction generates a fresh change address, and unnecessary forwarding transactions are eliminated.

This significantly improves on-chain privacy — previously, all funds were consolidated into a single output address that was reused for every payout and change output, making it trivial to link all DFX Bitcoin transactions on-chain.

Key changes

  • Single node: Remove BTC_INPUT/BTC_OUTPUT separation, use one Bitcoin Core wallet
  • No forwarding: Set forwardRequired=false — deposits stay in the wallet, no intermediate forward transactions (saves fees)
  • Fresh change addresses: Every sendMany call generates a new address via getnewaddress instead of reusing a fixed address
  • UTXO locking: lock_unspents: true prevents race conditions on parallel payouts
  • Native SegWit: New deposit addresses use bech32 (bc1q) instead of p2sh-segwit
  • UTXO entity: New BitcoinUtxo entity + repository + service for individual UTXO tracking in the database
  • Downstream: BuyFiatRegistration and BuyFiat return logic updated to handle COMPLETED status alongside FORWARD_CONFIRMED

Server setup required before deploy

  1. Create new descriptor wallet: bitcoin-cli createwallet "dfx" false false "" false true
  2. Enable avoid_reuse: bitcoin-cli -rpcwallet=dfx setwalletflag avoid_reuse true
  3. Transfer funds from old input/output wallets to new wallet
  4. Update env vars: NODE_BTC_URL_ACTIVE / NODE_BTC_URL_PASSIVE

Test plan

  • TypeScript compiles without errors
  • All 907 tests pass (lint, format, build verified)
  • DEV: Deposit received → UTXO tracked in DB, no forward TX, PayIn status goes directly to COMPLETED
  • DEV: Payout sent → Bitcoin Core selects UTXOs automatically, fresh change address generated
  • Verify listunspent shows no reused addresses

Replace the two-node Bitcoin architecture (input/output) with a single
node and descriptor wallet. Addresses are never reused — every deposit
gets a unique address and every transaction uses a fresh change address.

- Remove BTC_INPUT/BTC_OUTPUT node separation
- Set forwardRequired=false to skip unnecessary forwarding transactions
- Generate fresh change addresses via getnewaddress per transaction
- Add lock_unspents to prevent UTXO race conditions
- Switch deposit address type from p2sh-segwit to native segwit (bech32)
- Add BitcoinUtxo entity for individual UTXO tracking
- Update downstream services to handle COMPLETED PayIn status
@TaprootFreak
Copy link
Copy Markdown
Collaborator Author

Open items before deploy

Code (follow-up commit):

  • Wire BitcoinUtxoService into the Bitcoin register strategy — persist discovered UTXOs to the bitcoin_utxo table
  • Generate DB migration for the new bitcoin_utxo table

Server setup (manual, before switching env vars):

  • Create new descriptor wallet: bitcoin-cli createwallet "dfx" false false "" false true
  • Enable avoid_reuse: bitcoin-cli -rpcwallet=dfx setwalletflag avoid_reuse true
  • Transfer funds from old input + output wallets to the new wallet
  • Update env vars: NODE_BTC_URL_ACTIVE / NODE_BTC_URL_PASSIVE (replace old NODE_BTC_INP_* / NODE_BTC_OUT_*)
  • Remove old env vars: BTC_OUT_WALLET_ADDRESS, NODE_BTC_INP_URL_ACTIVE, NODE_BTC_INP_URL_PASSIVE, NODE_BTC_OUT_URL_ACTIVE, NODE_BTC_OUT_URL_PASSIVE

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