Skip to content

fix(bitcoin): round send fee_rate to 3 decimals#3729

Draft
TaprootFreak wants to merge 1 commit into
developfrom
fix/bitcoin-fee-rate-precision
Draft

fix(bitcoin): round send fee_rate to 3 decimals#3729
TaprootFreak wants to merge 1 commit into
developfrom
fix/bitcoin-fee-rate-precision

Conversation

@TaprootFreak
Copy link
Copy Markdown
Collaborator

Summary

The BTC payout pipeline silently stalled today (2026-05-20) for ~80 minutes — every sendmany/send RPC was rejected by Bitcoin Core with Invalid amount (error code -3). A 120k EUR buy-crypto (and several smaller ones) sat in Created until the stuck batch was manually cleared.

Root cause

Bitcoin Core's send / sendmany RPC parses the fee_rate argument with decimals=3 (source):

// Fee rates in sat/vB cannot represent more than 3 significant digits.
cc.m_feerate = CFeeRate{AmountFromValue(fee_rate, /*decimals=*/3)};

ParseFixedPoint returns false when the parsed value has more than 3 decimal places, which AmountFromValue re-throws as "Invalid amount".

Our fee-rate computation chain produces values with floating-point artifacts:

estimatesmartfee(1) -> 0.00001935 BTC/kvB
                    * 100000 = 1.9349999999999998   (binary64 imprecision)
                    * 2.0    = 3.8699999999999997   (cpfpFeeMultiplier)
JSON.stringify       = "3.8699999999999997"          (16 decimals)
Bitcoin Core         -> "Invalid amount"

Reproduced against the live BTC output node:

$ bitcoin-cli -named send outputs='[...]' fee_rate=3.8699999999999997 ...
error code: -3
error message: Invalid amount

$ bitcoin-cli -named send outputs='[...]' fee_rate=3.87 ...
   (accepted; fails later with "Insufficient funds" — expected, wallet was drained)

This also explains:

  • Only Bitcoin was affected (other chains don't go through rpc.send with a sat/vB fee_rate).
  • Recovery was non-deterministic — the loop unstuck itself when estimatesmartfee happened to return a value that survived the multiplication without artifacts.

Fix

Round the computed sat/vB fee rate to 3 decimal places in BitcoinBasedFeeService.getSendFeeRate(), which is the single source consumed by PayoutBitcoinService.sendUtxoToMany and the dex Bitcoin strategies.

Test plan

  • Added unit test in bitcoin-fee.service.spec.ts covering the exact floating-point case (1.935 * 2 -> 3.87, not 3.8699999999999997).
  • npm run lint, npm run format:check, npm run build, full Bitcoin fee test suite: all green locally.
  • Verify on DEV that BTC payouts continue to broadcast normally after deploy.

Bitcoin Core's send/sendmany RPC parses fee_rate with decimals=3 via
ParseFixedPoint and rejects values with more precision via "Invalid amount"
(error code -3). JS floating-point can produce values like
1.935 * 2 = 3.8699999999999997, which silently stalls the BTC payout pipeline.

Round the computed sat/vB fee rate to 3 decimals at the source so every
Bitcoin send RPC receives a value Bitcoin Core can parse.
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.

2 participants