fix(receive): default Link tab + embed boarding address in BIP-21#58
Conversation
- 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.
There was a problem hiding this comment.
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
-
Default tab switched from Address → Link (the BIP-21 URI). The
active/show activeclasses move from#address-tabto#link-tab. Correct UX call — scan-and-pay flow wants the unified QR first. -
BIP-21 construction replaced inline
$"bitcoin:?ark={Model.Address}"withArkadeBip21Builder, the same builder used by checkout (ArkadePaymentLinkExtension). This embeds the boarding address in the BIP-21 path position when available, producingbitcoin:<boardingAddr>?ark=<arkAddr>— non-Ark wallets see a payable onchain target; Ark-aware wallets use theark=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()emitsbitcoin:?ark=...(empty path). Traced throughArkadeBip21Builder.cs:125.Model.Address!null-forgiveness at line 57 is guarded by theif (hasAddress)check at line 54 (hasAddress = !string.IsNullOrEmpty(Model.Address)). Safe.Model.BoardingAddresspassed via ternary at line 58 —nullwhen!hasBoarding. Correct.- Tab state consistency: exactly one pill gets
active, exactly one pane getsshow 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 —
ArkadeBip21BuilderAPI 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
…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.
Receive page: Link tab default + boarding address in the BIP-21
Two small fixes to the Arkade Receive page (
Views/Ark/Receive.cshtml):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.
BIP-21 now includes the boarding address when one has been generated. Switched the inline string from
bitcoin:?ark=<arkAddress>to usingArkadeBip21Builder— 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
activeclass moved, inline string replaced with the canonical builder; no other behaviour change).CS####errors locally; remaining 2 errors are a local file-lock from a running BTCPay dev process — CI builds cleanly).build+E2Egreen.Independent of #55 (asset PR) and #57 (README) — fresh branch off current master.