Skip to content

feat: recheck on-chain required amount against actual UTXO count - #930

Closed
dangershony wants to merge 2 commits into
mainfrom
feat/onchain-dynamic-utxo-recheck
Closed

dangershony wants to merge 2 commits into
mainfrom
feat/onchain-dynamic-utxo-recheck

Conversation

@dangershony

@dangershony dangershony commented Jul 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes the multi-UTXO payment bug: signing spends all UTXOs on the funding address at ~68 vB each, but the displayed on-chain amount assumed one input. After funds arrive, PayToOnChainAddressAsync now recomputes the required amount for the actual detected UTXO count (PaymentFlowConfig.OnChainRequiredForUtxoCount) and keeps monitoring for the shortfall with a clear message, instead of failing at signing with "Insufficient funds". Wired for the invest flow only (InvestPageViewModel.CreatePaymentFlow); deploy flow intentionally not wired.

Supersedes #929 (closed).

Rebase notes

  • Rebased onto latest main. The old hardcoded 252 + stageCount*43 formula is gone: the new PaymentFlowConfig.EstimateOnChainRequired(..., inputCount) overload delegates to Angor.Shared.Protocol.InvestmentFeeEstimator (no duplicated formula).
  • Added InvestmentFeeEstimatorTests covering 1, 2, 3 inputs (each extra input adds 68 * feeRate sats).
  • Monitor result shape (TotalAmount.Sats, DetectedUtxos.Count) verified against current MonitorAddressForFunds.

Tests

Angor.Shared.Tests, Angor.Sdk.Tests and LayoutRegression tests pass. App.Desktop builds clean (App.sln can't build locally without the iOS workload).

Caveats / follow-ups

  • The top-up monitor reuses MonitorAddressForFunds (mempool-based). If the first payment confirms before the top-up arrives, aggregate detection may need revisiting. Recommend a signet UAT run with a deliberately split payment before merging.
  • Follow-up: the web app (InvestView.razor) has the same single-UTXO assumption; not touched here.

@dangershony

Copy link
Copy Markdown
Member Author

I am not convinced this commit should go in

…r funds arrive

The signing transaction for on-chain invoice payments spends ALL UTXOs on the
funding address and pays ~68 vB per input. If the user's payment arrives as
multiple UTXOs (two separate sends, exchange withdrawal splits, RBF leftovers),
the originally displayed amount no longer covers the miner fee, and
BuildInvestmentDraft fails with 'Insufficient funds' after the payment was
declared received.

Add PaymentFlowConfig.OnChainRequiredForUtxoCount: after MonitorAddressForFunds
succeeds, recompute the required amount for the actual detected UTXO count. If
the received total is short, tell the user the exact shortfall and keep
monitoring for the top-up instead of proceeding to a signing failure.

Also add an EstimateOnChainRequired overload that accepts an input count.
@dangershony
dangershony force-pushed the feat/onchain-dynamic-utxo-recheck branch from 80ebefe to 11fdb82 Compare October 15, 2026 10:39
@dangershony

Copy link
Copy Markdown
Member Author

Closing in favor of a different approach: instead of recomputing the required amount per detected UTXO and asking the user to top up the invoice address (which has a moving-target problem — each top-up adds an input and raises the fee — and a mempool-only monitor race when the first payment confirms mid-wait), we'll detect >1 UTXO and redirect the user to the existing pay-from-wallet path. The funds already land in the wallet (MonitorAddressForFunds saves detected UTXOs to account info), and AddInputsAndSignTransaction does proper coin selection with per-input fees, so no estimator changes or top-up loop are needed.

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