Description
When an Arkade invoice with an amount is generated (e.g. via the POS) and scanned as a QR code with Arkade Wallet, the wallet does not populate the amount field. ZEUS and Phoenix handle this correctly; Edge Wallet has the same issue. This suggests a URI parsing problem in wallets that don't follow a strict BIP21 reading path.
Steps to Reproduce
- Create an Arkade invoice with a specific amount (tested via the POS).
- Display the QR code for the Arkade payment method.
- Scan with Arkade Wallet → amount field is empty.
- Scan with ZEUS or Phoenix → amount is correctly pre-filled.
Root Cause Analysis
The BIP21 URI generated by ArkadeBip21Builder (BTCPayServer.Plugins.ArkPayServer/PaymentHandler/ArkadeBip21Builder.cs) takes this form when no onchain address is present:
bitcoin:?amount=0.001&ark=tark1...&lightning=lnbc...
The URI has an empty authority / path (bitcoin: followed immediately by ?). This is technically valid per BIP21 (address is optional in extended usage), but many wallet parsers expect the canonical form:
bitcoin:ADDRESS?amount=0.001&ark=tark1...
ZEUS and Phoenix are permissive and parse the query string regardless. Wallets with stricter parsers — including the current Arkade Wallet (ts-sdk src/utils/bip21.ts) — split on ? and only read query params if they find an explicit address part, or may reject the URI silently.
Looking at src/utils/bip21.ts in arkade-os/ts-sdk:
const [address, query] = withoutPrefix.split('?');
const params: BIP21Params = {};
if (address) {
params.address = address.toLowerCase();
}
if (query) {
const queryParams = new URLSearchParams(query);
// parses amount here
}
When the URI is bitcoin:?amount=0.001&ark=tark1..., withoutPrefix is ?amount=0.001&ark=tark1.... Splitting on ? yields address = '' and query = 'amount=0.001&ark=tark1...'. The if (address) branch is skipped (correct), and if (query) should still execute — so the ts-sdk parser itself may be handling this correctly. The bug may be in the native Arkade Wallet (mobile) QR scanner layer, which might abort parsing before reaching the query string when it sees an empty address.
Possible Fixes
Option A — Always include a stub bitcoin: path (safest, no parser changes)
Ensure ArkadeBip21Builder.Build() never produces bitcoin:?. When no onchain address is available, use the ark address as the path (since some wallets that understand BIP21 extensions will handle bitcoin:tark1... gracefully), or omit the amount from the URI and encode it a different way.
However, putting an ark address as a BIP21 path could confuse Bitcoin-only wallets.
Option B — Fix the wallet-side URI parser (Arkade Wallet / ts-sdk BIP21)
In src/utils/bip21.ts, ensure parse() correctly handles bitcoin:?key=val (empty address, query present). A quick audit:
// withoutPrefix = '?amount=0.001&ark=tark1...'
const [address, query] = withoutPrefix.split('?');
// address = '', query = 'amount=0.001...' — this should work fine
This looks correct already — the issue is likely upstream of this (QR decode → URI dispatch → handler), possibly in a React Native QR library or deep link handler.
Option C — Investigate the Arkade Wallet (mobile) deep link / URI dispatch layer
The mobile wallet likely intercepts bitcoin: URIs via a deep link handler. If the handler pattern-matches on bitcoin:[A-Za-z0-9] (expecting an address immediately after :), it would fail for bitcoin:?.... Check the URI dispatch / intent filter / universal link handling code.
Affected Components
BTCPayServer.Plugins.ArkPayServer/PaymentHandler/ArkadeBip21Builder.cs — URI generation
- Arkade Wallet (mobile) — QR scan + URI dispatch layer
arkade-os/ts-sdk src/utils/bip21.ts — BIP21 parse utility (verify correctness)
- Edge Wallet (same issue — external, but useful to confirm URI format hypothesis)
Next Steps
- Determine the exact URI string being generated by BTCPayServer for a test invoice (add logging or inspect the QR).
- Confirm whether the same URI fed directly into Arkade Wallet via a tap link reproduces the issue (isolates QR scanning from URI parsing).
- If the URI format is the issue: change
ArkadeBip21Builder to either always include an onchain address or not include the empty bitcoin: path.
- If it's a wallet-side parsing bug: fix the URI handler in the Arkade Wallet mobile app.
Description
When an Arkade invoice with an amount is generated (e.g. via the POS) and scanned as a QR code with Arkade Wallet, the wallet does not populate the amount field. ZEUS and Phoenix handle this correctly; Edge Wallet has the same issue. This suggests a URI parsing problem in wallets that don't follow a strict BIP21 reading path.
Steps to Reproduce
Root Cause Analysis
The BIP21 URI generated by
ArkadeBip21Builder(BTCPayServer.Plugins.ArkPayServer/PaymentHandler/ArkadeBip21Builder.cs) takes this form when no onchain address is present:The URI has an empty authority / path (
bitcoin:followed immediately by?). This is technically valid per BIP21 (address is optional in extended usage), but many wallet parsers expect the canonical form:ZEUS and Phoenix are permissive and parse the query string regardless. Wallets with stricter parsers — including the current Arkade Wallet (ts-sdk
src/utils/bip21.ts) — split on?and only read query params if they find an explicit address part, or may reject the URI silently.Looking at
src/utils/bip21.tsinarkade-os/ts-sdk:When the URI is
bitcoin:?amount=0.001&ark=tark1...,withoutPrefixis?amount=0.001&ark=tark1.... Splitting on?yieldsaddress = ''andquery = 'amount=0.001&ark=tark1...'. Theif (address)branch is skipped (correct), andif (query)should still execute — so the ts-sdk parser itself may be handling this correctly. The bug may be in the native Arkade Wallet (mobile) QR scanner layer, which might abort parsing before reaching the query string when it sees an empty address.Possible Fixes
Option A — Always include a stub
bitcoin:path (safest, no parser changes)Ensure
ArkadeBip21Builder.Build()never producesbitcoin:?. When no onchain address is available, use the ark address as the path (since some wallets that understand BIP21 extensions will handlebitcoin:tark1...gracefully), or omit the amount from the URI and encode it a different way.However, putting an ark address as a BIP21 path could confuse Bitcoin-only wallets.
Option B — Fix the wallet-side URI parser (Arkade Wallet / ts-sdk BIP21)
In
src/utils/bip21.ts, ensureparse()correctly handlesbitcoin:?key=val(empty address, query present). A quick audit:This looks correct already — the issue is likely upstream of this (QR decode → URI dispatch → handler), possibly in a React Native QR library or deep link handler.
Option C — Investigate the Arkade Wallet (mobile) deep link / URI dispatch layer
The mobile wallet likely intercepts
bitcoin:URIs via a deep link handler. If the handler pattern-matches onbitcoin:[A-Za-z0-9](expecting an address immediately after:), it would fail forbitcoin:?.... Check the URI dispatch / intent filter / universal link handling code.Affected Components
BTCPayServer.Plugins.ArkPayServer/PaymentHandler/ArkadeBip21Builder.cs— URI generationarkade-os/ts-sdksrc/utils/bip21.ts— BIP21 parse utility (verify correctness)Next Steps
ArkadeBip21Builderto either always include an onchain address or not include the emptybitcoin:path.