Title: Bitcoin Cash Payment Protocol
Type: Standards
Layer: Applications
Maintainer: Jason Dreyzehner
Status: Draft
Initial Publication Date: 2023-05-31
Latest Revision Date: 2023-05-31
Version: 0.1.0
Table of Contents
A standard for sharing Bitcoin Cash and CashToken payment information via Uniform Resource Identifiers (URIs) and a web-based payment protocol.
This proposal does not require coordinated deployment.
Existing standards for sharing payment information (BIP21, BIP70, BIP71, BIP72, BIP73, JSON Payment Protocol, and JSON Payment Protocol v2) do not address standardization of payments using CashTokens and also fail to accommodate recent market changes: the widespread usage of alternative cryptocurrency systems, the existence of long-term splits in cryptocurrencies, and the evolution of industry practices in cryptocurrency acceptance.
Additionally, existing standards require developers to reconcile implementation details from multiple, sometimes-conflicting documents. In some cases, portions of standards have fallen out of use by industry, but standards documents do not accurately reflect current practice. This proposal aims to serve as a primary reference document for new Bitcoin Cash payment protocol implementations and as a foundation for future standards.
(wip)
- Wallets should indicate support for receiving and sending CashTokens by appending
?t
(or&t
) to backwards-compatible (version0
and1
) addresses. - To request specific transfers of CashTokens, wallets must use CashToken-supporting addresses (v2 and v3 CashAddresses) and new payment URI parameters:
c
(category),f
(fungible token amount),n
(NFT commitment), ands
(satoshis). - The specification maintains compatibility with existing applications of BIP21, BIP73, JSON Payment Protocol, and JSON Payment Protocol v2.
- New MIME types and relevant extensions to BIP72, BIP73, BCMR, and JSON Payment Protocol v2 are defined.
A Bitcoin Cash Payment URI is:
- A request for a single transaction paying to an address using a single output, where all provided parameters modify the properties of the requested output, or
- Connection information for another protocol by which Bitcoin Cash and/or CashToken payment information is to be transmitted.
A non-normative summary of the payment URI syntax:
bitcoin[cash]:[address][?[t][&s=<satoshis>][&e=<expiration_timestamp>][&m=<message>][&r=<request_url>][&c=<category_hex>][&f=<fungible_token_amount>][&n=<nft_commitment_hex>][&<param>=<value>]]
Compatibility with BIP21 is also supported:
bitcoin[cash]:[address][?[t][&amount=<decimal_amount_BCH>][&message=<message>][&r=<request_url>]]
In further detail:
- The URI scheme must be
bitcoincash
orbitcoin
(see Support forbitcoin
URI scheme). - The
address
is a Bitcoin Cash address in CashAddress format; ifaddress
is not provided, ther
parameter (Request URL) is required. - Any number of unique, optional query parameters may follow
?
, in any order, with each definition separated by&
.
Parameter | Description | Additional Validation When Present |
---|---|---|
c |
The category identifier of the requested token(s), hex-encoded in user interface order1. | Error if f and/or n are not set. Error if address is not CashToken-supporting (e.g. version 2 and 3 CashAddresses). Error if amount is set (s may be used). |
e |
The Unix timestamp (64-bit) at which this URI expires. For the purpose of expiration, payments are considered to have occurred at the moment they are heard over the public network (rather than the time at which they are confirmed in a block). | Error if the indicated expiration time has passed. Error if amount is set (s may be used). |
f |
The fungible token amount requested in category c tokens. The amount is in terms of on-chain fungible token units, without respect for display standards. E.g. for a category in which 100 fungible tokens are considered to be 1.00 XAMPL , f=100 would be a request for 1.00 XAMPL . |
Error if c is not set. |
m |
A message that describes the transaction to the user. The message must be utf8-based, percent encoded; uppercase letters should also be percent encoded for reliable transmission2. | Error if message is also set. |
n |
The requested non-fungible token commitment of category c . The commitment must be hex-encoded, e.g. n=01 requests an NFT with commitment 0x01 ; n or n= requests an NFT with an empty commitment. |
Error if c is not set. |
r |
An HTTPS request URL, similar to BIP72, but used by the below described Payment Protocol. The https:// is implied and must be omitted (see Behavior of r parameter). If provided, all other parameters are ignored (other parameters may be used as a fallback for implementations without full payment protocol support). |
|
s |
The requested number of satoshis, e.g. s=123456 is a request for 0.00123456 BCH . If s is not set, the minimum value for the requested output (dust limit) is implied. |
Error if amount is also set. |
Compatibility | ||
t |
The receiver can safely receive CashTokens. Implied by CashToken-supporting v2 and v3 CashAddresses. The t parameter should only be used for backwards-compatibility; specific token requests must use a token-aware address (see the c parameter). |
Error if amount , c , or s is also set. |
amount |
The requested amount in whole BCH, e.g. amount=.00123456 is a request for 0.00123456 BCH . Included for backwards-compatibility with BIP21, but the s parameter is recommended for applications not requiring BIP21 compatibility. (See Inclusion of s parameter.) |
Error if s is also set. |
message |
Identical to m , included for backwards-compatibility with BIP21. Note that the BIP21 label parameter is not supported. |
Error if m is also set. |
<custom> |
An unknown, custom parameter that implementations can safely ignore. |
Notes
- This is the byte order typically seen in block explorers and user interfaces (as opposed to little-endian byte order, which is used in standard P2P network messages). For reference, the genesis block header in this byte order is little-endian –
000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
– and can be produced by this script:<0x0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c> OP_HASH256 OP_REVERSEBYTES
. - Most percent-encoding libraries do not percent-encode uppercase letters; for lossless transmission over case-insensitive protocols like Payment URI Alphanumeric Mode, URI generators must also percent-encode all uppercase letters. An example JavaScript implementation is provided below.
/**
* Encode a message for inclusion in a payment URI. This method differs from
* `encodeURIComponent` in that it encodes uppercase letters and does not encode
* `:`, `/`, or `$` (all transmissible in alphanumeric mode).
*/
const encodeMessage = (message) =>
encodeURI(message).replace(
/[^A-Za-z0-9 $%*\-\./:]|(?<!(?:%)|(?:%[A-F0-9]))[A-Z]/g,
(char) => '%' + char.charCodeAt(0).toString(16).toUpperCase()
);
/**
* Decode a percent-encoded message which may have been converted to uppercase
* for transmission in alphanumeric mode. As uppercase letters are percent
* encoded, all other letters are assumed to be intended for lower case display.
*/
const decodeMessage = (message) => decodeURIComponent(message.toLowerCase());
Payment URI Test Vectors
The following examples demonstrate well-formed payment URIs.
Description | Parameters | URI |
---|---|---|
v0 address | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl |
|
v0 address, token support | t |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t |
v0 address, token support, web-safe URI | t |
bitcoin:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t |
v0 address, token support, backwards-compatible message | t , message of test |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&message=test |
v0 address, token support, message | t , m of Tip for Alice at Venue |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&m=%54ip%20for%20%41lice%20at%20%56enue |
v0 address, token support, message, expiration | t , m of Tip for Bob at Venue , expiration of 2022-11-15T12:00:00.000Z |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&e=1668513600&m=%54ip%20for%20%42ob%20at%20%56enue |
v2 address (implicit token support) | bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v |
|
v2 address (implicit token support), web-safe URI | bitcoin:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v |
|
v2 address, satoshis | s=123456 |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?s=123456 |
v0 address, satoshis, expiration | s=123400 , expiration of 2023-05-15T12:00:00.000Z |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=123400&e=1684152000 |
Payment Protocol-Only | r=example.com/pay/1234 |
bitcoincash:?r=example.com/pay/1234 |
Payment Protocol-Only, web-safe URI | r=example.com/pay/1234 |
bitcoin:?r=example.com/pay/1234 |
Payment Protocol; falls back to v0 address, BIP21 amount | r=example.com/pay/1234 , amount=.001234 |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?amount=.001234&r=example.com/pay/1234 |
Payment Protocol; falls back to v0 address, satoshis, and expiration | r=example.com/pay/1234 , s=123400 , expiration of 2023-05-15T12:00:00.000Z |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=123400&e=1684152000&r=example.com/pay/1234 |
Payment Protocol; falls back to v0 address, token support, message | r=example.com/tip/1234 , t , m of Tip for Bob, Venue |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?r=example.com/tip/1234&t&m=%54ip%20for%20%42ob%2C%20%56enue |
v0 address, BIP21-compatible amount and message | amount=1 (1.00000000 BCH ), message of Test at ACME (10% Friends & Family Discount) |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?amount=1&message=%54est%20at%20%41%43%4D%45%20%2810%25%20%46riends%20%26%20%46amily%20%44iscount%29 |
v0 address, satoshi amount and message | s=12345 (0.00012345 BCH ), m of Multi\nLine\nMessage: T̶̀est |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=12345&m=%4Dulti%0A%4Cine%0A%4Dessage%3A%20%54%CD%80%CC%B6est |
v2 address, 10,000 FT request, minimum satoshis | c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 ,f=10000 |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000 |
v2 address, 10,000 FT request, 1000 satoshis | c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 , f=10000 , s=1000 |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000&s=1000 |
v2 address, 10,000 FT request, zero-byte NFT, minimum satoshis | c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 , f=10000 , n |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000&n |
v2 address, 10,000 FT request, zero-byte NFT, 1000 satoshis | c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 , f=10000 , n |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000&n&s=1000 |
v2 address, NFT commitment, minimum satoshis | c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 , NFT commitment of 0x01 |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&&n=01 |
v0 address, unknown optional parameter | custom=value |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?custom=value |
The following examples demonstrate malformed payment URIs. For each, implementations should consider returning the error message, This payment request uses an invalid or unknown encoding. ${error}
, with each error
indicated below:
Error | URI |
---|---|
No address or request URL is provided. | bitcoincash:?amount=1 |
No address or request URL is provided. | bitcoincash:?s=1000 |
Request includes multiple instances of the amount parameter. |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?amount=1&amount=1 |
Request includes multiple instances of the r parameter. |
bitcoincash:?r&r=example.com/pay/1234 |
Request includes multiple instances of the s parameter. |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=123456&s=123456 |
Request includes multiple instances of the f parameter. |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000&f=1 |
Token-accepting request requires a token-aware address. | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&amount=1 |
Token-accepting request requires a token-aware address. | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&s=1000 |
Token-accepting request requires a token-aware address. | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000 |
Expiring request uses the deprecated amount parameter. |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?amount=1&e=1684152000 |
Both s and amount are set. |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=123456&amount=.00123456 |
Both m and message are set. |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?m=abc&message=abc |
Token request is missing a fungible amount and/or NFT commitment. | bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428 |
Token request pays to an address without token support. | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10 |
Token request pays to an address without token support. | bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t&c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10 |
Token request uses the ambiguous amount parameter. |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10&amount=.0001 |
Token request is missing a token category. | bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?f=10 |
Token request is missing a token category. | bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?n |
Token request is missing a token category. | bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?n=00 |
Payment URI Alphanumeric Mode is defined to enable high-density encoding of payment URIs in QR codes. To convert a payment URI to alphanumeric mode:
- Convert all characters to uppercase.
- Convert reserved characters to their alphanumeric mode equivalent:
?
becomes:
,=
becomes-
, and&
becomes+
.
- Optionally, instances of
%20
(space) and%24
($
) may be decoded withinm
/message
values for maximum compression.
Use of alphanumeric mode is recommended for all QR-encoded payment URIs requesting tokens and for use cases in which BIP21 backwards-compatibility is not required.
Alphanumeric Mode Test Vectors
URI | Alphanumeric Mode |
---|---|
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl |
BITCOINCASH:QR7FZMEP8G7H7YMFXY74LGC0V950J3R2959LHTXXSL |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?t |
BITCOINCASH:QR7FZMEP8G7H7YMFXY74LGC0V950J3R2959LHTXXSL:T |
bitcoincash:?r=example.com/pay/1234 |
BITCOINCASH::R-EXAMPLE.COM/PAY/1234 |
bitcoin:?r=example.com/pay/1234 |
BITCOIN::R-EXAMPLE.COM/PAY/1234 |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=1234 |
BITCOINCASH:QR7FZMEP8G7H7YMFXY74LGC0V950J3R2959LHTXXSL:SAT-1234 |
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v?c=0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428&f=10000 |
BITCOINCASH:ZR7FZMEP8G7H7YMFXY74LGC0V950J3R295Z4Y4GQ0V:C-0AFD5F9AD130D043F627FAD3B422AB17CFB5FF0FC69E4782EEA7BD0853948428+F-10000 |
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl?s=1000&m=%54est%20at%20%41%43%4D%45%20%2810%25%20%46riends%20%26%20%46amily%20%44iscount%29 |
BITCOINCASH:QR7FZMEP8G7H7YMFXY74LGC0V950J3R2959LHTXXSL:S-1000+M-%54EST AT %41%43%4D%45 %2810%25 %46RIENDS %26 %46AMILY %44ISCOUNT%29 |
A JSON-based payment protocol is defined for Bitcoin Cash and CashToken payments; this protocol is fully compatible with and extends the multi-asset JSON Payment Protocol v2.
Work in progress:
- Support BIP72 and BIP73-style GET requests:
Accept
=application/bitcoincash-payment-request+0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428,application/bitcoincash-payment-request,application/payment-options
- User preference: category
0afd5f9ad130d043f627fad3b422ab17cfb5ff0fc69e4782eea7bd0853948428
, BCH, or falls back toapplication/payment-options
- User preference: category
x-paypro-version
=2
application/payment-options
:currency
is either"BCH"
or hex-encoded CashTokencategory
network
may bemain
,chip
,test4
, or a BCMR split ID
paypro
extension for BCMR identities, uses Key Distribution format, omitowner
(superseded by identityname
).
The URI parameters specified by this proposal reflect changes in the marketplace since BIP21 was initially introduced:
- Less-than-expected demand within URI parameter namespace – BIP21 anticipated that many new, application-specific parameters would be added by specific wallets and implementations. This growth in URI parameter usage did not materialize in the ensuing decade; new use cases instead focused on changes or expansions to various payment protocols.
- Increased importance of brevity – both scannable codes and Near Field Communication (NFC) became widely adopted by nearly every modern computing device; QR codes became a primary feature of mainstream cryptocurrency usage (especially as camera performance improved and costs fell), and globally, NFC became a common interface for in-person payments. In both cases, saving bytes within payment URIs became more important: additional bytes can require increased QR code size or larger NFC tag storage capacity.
Given these changes in the marketplace, this proposal aims to maximize URI efficiency in the long-term by defining an upgrade path from the loosely BIP21-based standard used by today's Bitcoin Cash ecosystem. All new URI parameters use a single identifying character, the message
parameter may be optionally shortened to m
, amount
is replaced by s
in token use cases (and optionally in other cases), and an alphanumeric mode for QR codes is introduced.
While this proposal allows backwards-compatible payment URIs to indicate support for receiving CashTokens by appending ?t
/&t
, payment URIs requesting specific payments in CashTokens are required to include a CashToken-supporting address (e.g. version 2
or 3
CashAddresses). This requirement prevents pathological cases in which a wallet without token support quietly ignores token-related parameters and misleads users into making incorrect payments.
To illustrate, consider a payment URI requesting a $1 stablecoin payment: a token-unaware wallet might quietly ignore unknown parameters (c
, f
, s
, etc.), and instead simply pre-fill the address in a payment view. Unaware of the issue, some users might manually enter "$1", causing the wallet to compute an equivalent value payment in BCH rather than the requested stablecoin. If the user sends this payment, the receiver will not only have received a different asset than expected (at an exchange rate chosen by the user's wallet), but refunding this payment will incur support and operational costs.
To prevent such errors, token-requesting payment URIs are required to use CashToken-supporting addresses.
This proposal requires use of the new s
(satoshis) parameter rather than the existing BIP21 amount
parameter for payment URIs requesting CashTokens; this policy is valuable for payment error prevention, privacy, and encoding efficiency.
The word "amount" can be reasonably interpreted as either an amount of Bitcoin Cash or a fungible token amount, so usage of the amount
parameter in newer, token-specific applications would increase the risk of misinterpretation and software bugs.
Additionally, the whole-amount rounding bias of the amount
parameter is incompatible with good wallet privacy practices: rounded values make transaction clustering analysis easier, so well-designed wallets should almost never send round amounts. For this reason, it can be concluded that privacy-preserving amount values are more efficiently described in terms of satoshis. Amounts greater than 1 BCH save at least one character (a decimal), and amounts smaller than 1 BCH may drop multiple placeholder 0
digits; these savings are in addition to the 5 characters saved by the shorter parameter name.
Note, existing applications may continue to use the BIP21 amount
parameter indefinitely; this requirement applies only to new applications creating token-specific payment URIs.
The BIP21 label
parameter is not commonly acknowledged by modern wallets as it is easily used in attacks that mislead novice users. Additionally, labelling individual addresses encourages poor security and privacy practices like widespread address publication and address reuse.
This proposal considers label
to be deprecated; it can be safely ignored by implementations. Bitcoin Cash Metadata Registries are a superior solution for transmitting authenticated addresses and address-like information, and the m
parameter (or equivalent, BIP21-compatible message
parameter) is generally a safer choice for all other use cases in which label
might have previously been used.
This proposal differs from BIP72 in that the r
parameter does not support alternatives to the HTTPS
protocol scheme. This is the established behavior of many BIP72 implementations, but lack of clarity in the initial specification has prevented many payment URI generators from omitting the https://
prefix, increasing URI length and the resulting complexity of QR-encoded URIs.
Note that this clarification does not inhibit the use of alternative protocols where a special Top-Level Domain (TLD) is established to indicate use of the protocol. For example, the Tor network uses the .onion
TLD in Tor addresses. Additionally, if future standards require indication of request URIs using non-HTTPS
protocol schemes, an alternative parameter name can be assigned for that use.
This proposal does not include a parameter for conveying a minimum required network fee rate (e.g. k
, a minimum fee rate per kilobyte). While a fee rate parameter might help merchants reduce payment errors during unusual network activity, the additional specification, implementation, and testing complexity outweigh any potential value.
On Bitcoin Cash, the minimum required network fee rate is a relay policy not enforced by block validation consensus. (As of 2023, the fee rate is conventionally set to 1000 satoshis per kilobyte.) In practice, this minimum required fee rate can only rise in cases where network transaction throughput exceeds the prevailing consensus block size limit for a sustained period. As the prevailing limit is set to a significant multiple of expected peak usage, such network conditions only occur during attempted network-wide denial of service attacks in which an attacker creates enough fee-paying transactions to crowd out real users over multiple blocks. Under these circumstances, wallets of real users should begin to temporarily increase their selected fee rate to have their transactions prioritized over the attacker; to continue impacting real network usage, the attacker must match or exceed these higher fee rates, geometrically increasing the cost of the attack at each step.
Given this background, including a minimum fee rate parameter in the proposed URI scheme is unlikely to meaningfully reduce payment errors during attacks: wallet software must already be capable of adapting fee rates to network conditions, so any hinting in URI requests simply duplicates this expected capability with greater delay (the URI's fee rate is necessarily computed before the reading wallet's fee rate). Additionally, the specified payment protocol enables merchants to specify a minimum fee rate, so applications with stricter settlement requirements can always specify a payment protocol request URL (r
parameter) without fallback URI parameters.
This proposal defines a payment URI alphanumeric mode which is specifically optimized for encoding efficiency within alphanumeric-encoded QR codes.
Alternatively, this proposal could standardize a "binary mode", where URI contents are instead packed into a binary-encoded QR code. However, such a mode would require significantly more specification and implementation complexity, and the binary mode would only reduce QR code complexity by a negligible amount beyond the proposed alphanumeric mode:
- CashAddresses already include carefully-designed, application-specific encoding and error correction:
- Encoding – mixed case and several easily confusable characters are omitted. This is important in edge cases where a user might be required to manually type or read an address aloud.
- Error detection – applications can detect up to 6 random errors or up to 8 character bursts of errors within most addresses. Error detection in binary-encoded QR codes would be less efficient and more opaque to end users.
- CashAddresses encode information at 5 bits per character; alphanumeric-encoded QR codes coincidentally encode information at 5.5 bits per character (for similar reasons), so only minimal theoretical efficiency gains are possible from encoding address information using QR code binary encoding. These minimal gains would require significant additional development and maintenance across all implementations.
- The density of other URI parameters could be increased via binary encoding, but this would again require significant increases in implementation complexity, and gains would only apply to a relatively small subset of real-world use cases:
- Payment Request URLs (
r
) are already very densely-packed by alphanumeric mode. - Messages (
m
ormessage
) with primarily lowercase characters are very densely-packed by alphanumeric mode. - Token categories (
c
) and NFT commitment requests (n
) only appear in more specialized URIs; they could be more efficiently packed either by a binary mode or by another encoding within alphanumeric mode (like bech32), but this would have negligible impact on QR code complexity1. - Numeric parameters (
f
ands
) occupy a minimal percentage of total URI length, so encoding savings are unlikely to be worth additional implementation complexity.
- Payment Request URLs (
Notes
- For example,
07a70ec6e0a325991e829daea5de1be1bb71e1ef4a04931cdddf567d8f60f676
might be encoded asq7nsa3hq5vjej85znkh2thsmuxahrc00fgzfx8xamat8mrmq7emq
(libauth.encodeBech32(libauth.regroupBits({bin: libauth.hexToBin('07a70ec6e0a325991e829daea5de1be1bb71e1ef4a04931cdddf567d8f60f676'), sourceWordLength: 8, resultWordLength: 5 }))
), saving 12 alphanumeric characters, but any URI withc
(category) defined must also define an address and eitherf
(fungible amount) orn
(NFT commitment). (Note, if a request URL –r
– were defined, none of the aforementioned parameters are required to be encoded in the URI itself, so again, density is not improved.) Altogether, we can expect the minimum overhead in this URI to be 113 characters (prefix and address: 54,c
parameter and bech32 encoded category: 55, additionalf
orn
parameter overhead: 4). At this length, the 12 character reduction does not reduce QR code complexity at all: regardless of bech32 encoding, both QR codes would be 53x53 modules. (atQuartile
QR code quality – 25% error correction).
This proposal recommends that wallets support the bitcoin
URI scheme in addition to the bitcoincash
scheme; the bitcoin
URI receives special treatment by web browsers, so wallets that register support for bitcoin
may be activatable in some contexts where browser policy might interfere with the bitcoincash
URI scheme. Additionally, it's common for multi-coin Bitcoin Cash wallets to also support BTC, so these wallets are easily capable of distinguishing and using both URI schemes.
Finally, most wallets can expect little overlap in real usage between BCH and BTC usage of bitcoin
URIs. Much of the BTC ecosystem has transitioned from BIP21 to alternative payment information sharing strategies (often for secondary networks); for example, BOLT11 recommends the lightning
URI scheme and considers the bitcoin
scheme to be a fallback measure. If meaningful usage overlap is expected – and the wallet does not also support BTC – the wallet may simply offer users the option to copy or re-open the bitcoin
URI in a different wallet.
This proposal strictly defines expected error behavior in parsing of payment URIs – unexpected conflicts are never ignored. This behavior minimizes subtle differences between implementations and maximizes flexibility for future standards: future standards can safely replace error behaviors without risk that non-supporting clients will partially-misinterpret the new standard.
To reduce scope, this proposal does not attempt to standardize the use of Bitcoin Cash or CashTokens in the Web Payment Request API; future CHIPs might provide usage recommendations.
The following software is known to support Bitcoin Cash Metadata Registries:
(pending initial implementations)
Thank you to Jonas Lundqvist, Tom Zander, Yashasvi S. Ranawat, Joemar Taganna, Mathieu Geukens, and bitcoincashautist for reviewing and contributing ideas leading to this proposal, providing feedback, and promoting consensus among stakeholders.
This section summarizes the evolution of this document.
- Draft v1.0.0
This document is placed in the public domain.