Standalone one-click invest page (web) + Fund/Subscribe and fee fixes - #934
Merged
Conversation
…ge-output fee calculation - IsInvestmentWindowOpen: Fund/Subscribe projects have no investment window (EndDate is unset), so treat them as always open - AddInputsFromAddressAndSignTransaction: include the change output in the tx size before computing the miner fee; previously the broadcast tx was ~31 vB larger than paid for, failing min relay fee (e.g. 316 < 319 at 1 sat/vB) - InvestorProject.CompleteProjectInvestment: AmountInvested was computed from ProjectInfo.Stages.Count which is 0 for dynamic-stage projects; sum taproot stage outputs instead
Turns the webapp into a single-purpose invest experience (angor-hub look and feel) aimed at a dedicated invest domain:
- /invest/{projectId} standalone page (EmptyLayout, no app navigation); legacy wizard moved to /invest-legacy
- Root landing: paste a project ID or follow a link from angor.io
- Deep-link project loading via indexer + Nostr relays, NIP-65 relay list merged into settings, network auto-detected from the project's NetworkName (auto-switch when no wallet exists)
- Temp wallet auto-created with a random local key: no password prompts; recovery phrase must be saved (copy/download) BEFORE any payment is requested; phrase re-viewable on demand
- Payment via on-chain address or Lightning (Boltz); leftover balance from a previous session is offered via a 'You already have funds' prompt instead of a wallet payment method
- Penalty threshold check mirrors the desktop flow: below-threshold Fund and Subscribe investments publish directly (with founder Nostr notification); above-threshold auto-publishes when founder signatures arrive
- Fund/Subscribe use FundingParameters with the selected dynamic stage pattern (was using the Invest-only overload)
- Indexer selection: defaults + ?indexer= URL parameter (persisted as primary) + footer Connection settings modal for indexers/relays
- Guarded 'delete wallet from this browser' flow with final seed display and explicit confirmation
- angor-hub design tokens in invest.css (dark theme default)
The deploy action wipes the gh-pages branch on every release, so the CNAME file must be part of the deployed output. Sets the invest app's production domain to app.angor.io (was beta.angor.io, previously only present as a manual file on the gh-pages branch).
The SDK/desktop app encrypts Nostr DM content (founder signature responses) with NIP-44, but the webapp's EncryptionService only supported NIP-04 (AES-CBC with '?iv=' separator) via the JS shim. The decrypt threw in JS and the investor page waited for founder approval forever. - EncryptNostrContentAsync now uses NIP-44 (same Nostr.Client code as the SDK) - DecryptNostrContentAsync auto-detects: '?iv=' -> legacy NIP-04, else NIP-44 - HandleSignatureReceivedAsync surfaces errors instead of swallowing them (it runs as a fire-and-forget relay callback) - Hero card shows the selected pattern's stage count for Fund/Subscribe
Deleting the wallet left the InvestorProject records in storage, so the page still rendered the invested/waiting states for a wallet that no longer exists. The records are unusable without the wallet's keys, so remove them on delete (RemoveInvestmentProject archives recovery signatures before deletion) and reset the page to the fresh invest state.
- Live indicator under the amount input showing whether the current amount needs founder approval (Invest: always; Fund: above penalty threshold, with the threshold shown; Subscribe: never). Uses the same shared IsInvestmentAbovePenaltyThreshold helper as the submit path so the indicator cannot disagree with the actual flow. - While waiting for founder approval, automatically re-check the relays every 30 seconds (same as Check Now); stops on approval/cancel/dispose. - Page now implements IDisposable, cancelling the signature poll and any orphaned invoice/Lightning monitors on navigation.
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.
Summary
Turns the Blazor webapp into a standalone single-page invest experience (intended for a dedicated invest domain), letting anyone invest in an Angor project with on-chain or Lightning payments — no pre-existing wallet, no password, no app navigation.
The invest page (
/invest/{projectId})/invest-legacyNetworkNamein the Nostr event (auto-switch + reload when no wallet exists locally)FundingParameters+ selected dynamic stage pattern (was using the Invest-only overload, which threw)?indexer=URL parameter (persisted as primary — for the hub's invest button) + footer Connection settings modal (indexers/relays, status, add custom)Shared fixes (benefit desktop/SDK too)
IsInvestmentWindowOpen: Fund/Subscribe have no investment window (EndDateunset) — treat as always openAddInputsFromAddressAndSignTransaction: fee was computed before the change output was added, so the broadcast tx underpaid min relay fee (316 < 319at 1 sat/vB); the change output is now included in the size measurementInvestorProject.CompleteProjectInvestment:AmountInvestedwas 0 for dynamic-stage projects (computed from emptyProjectInfo.Stages)Testing
Angor.Shared.Tests: 154/154 passAngor.Sdk.Tests: 323/323 pass (14 skipped)Follow-ups (out of scope)
<invest-domain>/invest/{projectIdentifier}?indexer=...