Skip to content

Standalone one-click invest page (web) + Fund/Subscribe and fee fixes - #934

Merged
dangershony merged 6 commits into
mainfrom
feature/standalone-invest-page
Jul 19, 2026
Merged

Standalone one-click invest page (web) + Fund/Subscribe and fee fixes#934
dangershony merged 6 commits into
mainfrom
feature/standalone-invest-page

Conversation

@dangershony

Copy link
Copy Markdown
Member

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})

  • Standalone layout with angor-hub look and feel (dark theme, hub design tokens); legacy wizard moved to /invest-legacy
  • Deep-link loading: indexer → Nostr relays (project info + profile), NIP-65 relay list merged into settings
  • Network auto-detected from the project's NetworkName in the Nostr event (auto-switch + reload when no wallet exists locally)
  • Temp wallet auto-created, no password — encrypted with a random key stored alongside in localStorage; recovery phrase must be saved (copy/download) before any payment address is shown, and is re-viewable any time
  • Payments: on-chain address or Lightning (Boltz reverse swap); leftover balance from a previous session is offered via a "You already have funds" prompt (resume / don't-pay-twice) instead of a wallet payment method
  • One-click completion: penalty threshold check mirrors the desktop flow — below-threshold Fund and Subscribe publish directly (founder notified over Nostr); above-threshold auto-publishes as soon as founder signatures arrive
  • Fund/Subscribe now build the transaction with FundingParameters + selected dynamic stage pattern (was using the Invest-only overload, which threw)
  • Indexer selection: defaults + ?indexer= URL parameter (persisted as primary — for the hub's invest button) + footer Connection settings modal (indexers/relays, status, add custom)
  • Guarded delete wallet from this browser flow (final seed display, explicit confirmation, blocked mid-approval)

Shared fixes (benefit desktop/SDK too)

  • IsInvestmentWindowOpen: Fund/Subscribe have no investment window (EndDate unset) — treat as always open
  • AddInputsFromAddressAndSignTransaction: fee was computed before the change output was added, so the broadcast tx underpaid min relay fee (316 < 319 at 1 sat/vB); the change output is now included in the size measurement
  • InvestorProject.CompleteProjectInvestment: AmountInvested was 0 for dynamic-stage projects (computed from empty ProjectInfo.Stages)

Testing

  • Angor.Shared.Tests: 154/154 pass
  • Angor.Sdk.Tests: 323/323 pass (14 skipped)
  • Manually verified end-to-end on a Fund project: fresh wallet → seed backup → on-chain payment → below-threshold direct publish → founder notification accepted by relays → success screen; plus leftover-funds reuse and wallet deletion

Follow-ups (out of scope)

…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.
@dangershony
dangershony merged commit 6fd0fba into main Jul 19, 2026
3 checks passed
@dangershony
dangershony deleted the feature/standalone-invest-page branch July 19, 2026 01:51
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