Skip to content

fix(receive): default Link tab + embed boarding address in BIP-21#58

Merged
Kukks merged 1 commit into
masterfrom
fix/receive-page-default-tab-bip21
May 20, 2026
Merged

fix(receive): default Link tab + embed boarding address in BIP-21#58
Kukks merged 1 commit into
masterfrom
fix/receive-page-default-tab-bip21

Conversation

@Kukks

@Kukks Kukks commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Receive page: Link tab default + boarding address in the BIP-21

Two small fixes to the Arkade Receive page (Views/Ark/Receive.cshtml):

  1. Default tab is now Link (the unified BIP-21 payment URI) instead of the bare Ark Address tab. A payer's flow is scan-and-pay, so the QR-friendly link is the practical default; the Address tab remains for copy/inspect.

  2. BIP-21 now includes the boarding address when one has been generated. Switched the inline string from
    bitcoin:?ark=<arkAddress> to using ArkadeBip21Builder — the same builder the checkout uses — which produces:
    bitcoin:<boardingAddress>?ark=<arkAddress>

    Wallets that only speak standard BIP-21 see the boarding address as the payable target; Ark-aware wallets pick up the ark= param too. Single source of truth between checkout and receive — no two paths to drift apart.

Why this matters

Before, a merchant generating both an Ark address and a boarding address still got a Link-tab URI that only referenced the Ark address — the boarding address was reachable only by switching tabs and copy-pasting. Embedding boarding in the unified link is what makes a single QR scan actually work for a non-Ark wallet.

Test plan

  • Diff confirmed minimal (tab active class moved, inline string replaced with the canonical builder; no other behaviour change).
  • Razor parses cleanly (no CS#### errors locally; remaining 2 errors are a local file-lock from a running BTCPay dev process — CI builds cleanly).
  • CI: build + E2E green.

Independent of #55 (asset PR) and #57 (README) — fresh branch off current master.

- The Link tab (unified BIP-21 payment URI) is now the default active
  tab on /receive, instead of the bare Ark Address tab. A wallet user
  scans-and-pays, so the link is the practical default; the address tab
  remains for copy/inspect.
- The Receive page now uses ArkadeBip21Builder (single source of truth
  with checkout) so the link includes the boarding address as the
  bitcoin:<onchain> target when one was generated:
    bitcoin:<boardingAddress>?ark=<arkAddress>
  Wallets that only speak standard BIP-21 see the boarding address as
  the payable target; Ark-aware wallets pick up the ark= param too.
  Previously the link was bitcoin:?ark=<arkAddress> — boarding wasn't
  surfaced anywhere reachable by a single QR scan.

@arkanaai arkanaai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arkana Code Review — APPROVE ✅

PR: fix(receive): default Link tab + embed boarding address in BIP-21
Scope: Views/Ark/Receive.cshtml only — 1 file, +17/−5, single commit.

What changed

  1. Default tab switched from Address → Link (the BIP-21 URI). The active / show active classes move from #address-tab to #link-tab. Correct UX call — scan-and-pay flow wants the unified QR first.

  2. BIP-21 construction replaced inline $"bitcoin:?ark={Model.Address}" with ArkadeBip21Builder, the same builder used by checkout (ArkadePaymentLinkExtension). This embeds the boarding address in the BIP-21 path position when available, producing bitcoin:<boardingAddr>?ark=<arkAddr> — non-Ark wallets see a payable onchain target; Ark-aware wallets use the ark= param. Single source of truth ✓

Verified

Scenario Result
hasAddress=true, hasBoarding=true bitcoin:<boarding>?ark=<arkAddr> — Link tab active ✓
hasAddress=true, hasBoarding=false bitcoin:?ark=<arkAddr> — Link tab active ✓
hasAddress=false, hasBoarding=true paymentLink=null, Link tab not rendered, Boarding tab gets active
hasAddress=false, hasBoarding=false Generate buttons shown, no tabs ✓
  • WithOnchainAddress(null) is safe — builder sets _onchainAddress = null, Build() emits bitcoin:?ark=... (empty path). Traced through ArkadeBip21Builder.cs:125.
  • Model.Address! null-forgiveness at line 57 is guarded by the if (hasAddress) check at line 54 (hasAddress = !string.IsNullOrEmpty(Model.Address)). Safe.
  • Model.BoardingAddress passed via ternary at line 58 — null when !hasBoarding. Correct.
  • Tab state consistency: exactly one pill gets active, exactly one pane gets show active, across all four scenarios. Verified in the Razor.
  • No protocol-critical changes (no VTXO handling, signing, forfeit, round, or exit path logic touched).
  • No cross-repo impact — ArkadeBip21Builder API surface unchanged, only a new consumer added.
  • No new code paths that need tests — this is a view-layer change using an already-tested builder.

Nits (non-blocking)

None. Clean diff, good comments in the Razor explaining the BIP-21 shape. The // Single source of truth comment at line 49-52 is a nice touch for future maintainers.

CI: build + E2E still pending at review time — recommend waiting for green before merge.


Reviewed by Arkana (opus) · aggressive protocol review · no protocol-critical flags

@Kukks Kukks merged commit 016a92b into master May 20, 2026
2 checks passed
@arkanaai arkanaai Bot mentioned this pull request May 20, 2026
5 tasks
Kukks added a commit that referenced this pull request May 20, 2026
…er flake) (#60)

FundedWallet_FullJourney_FundEstimateSendPayout has been flaking on
every recent master push (after #57 README, #58 Receive view, and #59
text-button — none of which touch coin selection). The failure is
build-intent returning a 200 with 'No valid VTXOs selected' in the
body, asserted against on line 109.

Diagnosis: TOCTOU between the early PollForSpendableCoinsAsync (line
56) and the build-intent POST. Between those two points the test
creates another store, browses pages, and runs estimate-fees — long
enough for a batch settlement or VTXO state shift to invalidate the
originally captured outpoints. build-intent's stricter coin validation
then rejects them.

Fix: re-poll right before the build-intent POST and use the refreshed
outpoints. 1-minute timeout (state should already be stable; if not,
fail fast with the existing polling helper's message). No product code
changed — pure test-resilience tightening. Successful runs add ~one
poll cycle (~3s); previously-flaky runs converge to stable outpoints
before submitting.
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