fix: shared invest fee estimation + nostr investment sync between web app and desktop - #952
Merged
dangershony merged 4 commits intoJul 25, 2026
Merged
Conversation
… web and desktop - Add InvestmentFeeEstimator (Angor.Shared): single source of truth for the on-chain amount required at a funding address (investment + Angor fee + investment-tx miner fee), with headroom for the Boltz claim fee on the lightning path. Desktop PaymentFlowConfig now delegates to it. - Webapp InvestView: size lightning invoices with the live median fee rate instead of hardcoded 2 sat/vB, ask for the full required amount on the on-chain invoice path, and build the investment tx with the same fee rate that was budgeted (fixes 'fee too low' / dust-change failures on single-UTXO Boltz claims). - Add NostrInvestmentStorageService (Angor.Shared): one shared implementation of the encrypted self-DM investments list (derive storage keys, encrypt, publish, lookup, dedup, newest-first decrypt fallback). Used by the SDK PortfolioService and the webapp (Invest, Investor, InvestView). - Webapp InvestView now saves the investments list to nostr after both publish paths, so investments made there are discoverable when the seed is imported in the desktop app. - PortfolioService: never cache an empty relay result and don't treat an empty local document as authoritative, so a transient relay failure can no longer permanently hide investments.
…nger used; InvestView.razor is the active invest page)
… don't resurrect Cancel previously removed the record only from the local cache. With the relay-fallback fix in GetByWalletId, an empty local list falls through to the relay, which still held the cancelled record and blocked reinvesting with 'You have already invested in this project' (caught by MultiInvestClaimAndRecover UAT).
…estimates Fund/Subscribe projects derive stages from the selected pattern, not ProjectInfo.Stages (which is empty for dynamic-stage projects). Use the pattern's StageCount when sizing lightning/on-chain invoice amounts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two user-reported failures when investing via Lightning on the web app, plus a cross-app discovery gap:
InvestView.razor) never appeared after importing the seed in the desktop app. That page only saved to browser localStorage � it never pushed the encrypted investments list to nostr, which is the mechanism the desktop uses to discover investments on wallet import.PortfolioServicecached an empty relay result to LiteDB and treated it as authoritative forever � one transient relay timeout permanently hid all investments.Fix (shared code used by both web app and desktop)
InvestmentFeeEstimator(Angor.Shared) � single source of truth for the on-chain amount required at a funding address (investment + Angor fee + investment-tx miner fee), with headroom for the locally-built Boltz claim fee on the lightning path. DesktopPaymentFlowConfig.EstimateOnChainRequirednow delegates to it (same numbers as before � no desktop behavior change).InvestView.razor: lightning invoices are sized with the live median fee rate; the on-chain invoice modal asks for (and monitors for) the full required amount; the investment tx is built with the same fee rate that was budgeted so estimate and build can never drift apart.NostrInvestmentStorageService(Angor.Shared) � one shared implementation of the encrypted self-DM investments list (storage-key derivation, encrypt, publish, relay lookup, dedup, newest-first decrypt fallback). Used by the SDKPortfolioServiceand the web app'sInvestView.razor(the active invest page; the legacy Invest/Investor pages are untouched).InvestView.razornow saves the investments list to nostr after both publish paths (direct and founder-approved), so web investments are discoverable when the seed is imported in the desktop app.PortfolioService: never caches an empty relay result and no longer treats an empty local document as authoritative � retries the relay on next load instead.Testing
WebApp.slnandApp.Desktopbuild clean