mirror of
				https://github.com/bitcoin/bips.git
				synced 2025-10-27 14:09:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			228 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| <pre>
 | |
|   BIP: 20
 | |
|   Layer: Applications
 | |
|   Title: URI Scheme
 | |
|   Author: Luke Dashjr <luke+bip@dashjr.org>
 | |
|   Comments-Summary: No comments yet.
 | |
|   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0020
 | |
|   Status: Replaced
 | |
|   Type: Standards Track
 | |
|   Created: 2011-01-10
 | |
|   License: BSD-2-Clause
 | |
| </pre>
 | |
| 
 | |
| BIP 0020 is based off an earlier document by Nils Schneider. '''And has been replaced by BIP 0021'''
 | |
| 
 | |
| ==Abstract==
 | |
| This BIP proposes a URI scheme for making Bitcoin payments.
 | |
| 
 | |
| ==Copyright==
 | |
| This BIP is licensed under the BSD 2-clause license.
 | |
| 
 | |
| ==Motivation==
 | |
| The purpose of this URI scheme is to enable users to easily make payments by simply clicking links on webpages or scanning QR Codes.
 | |
| 
 | |
| ==Specification==
 | |
| 
 | |
| === General rules for handling (important!) ===
 | |
| 
 | |
| Bitcoin clients MUST NOT act on URIs without getting the user's authorization.
 | |
| They SHOULD require the user to manually approve each payment individually, though in some cases they MAY allow the user to automatically make this decision.
 | |
| 
 | |
| === Operating system integration ===
 | |
| Graphical bitcoin clients SHOULD register themselves as the handler for the "bitcoin:" URI scheme by default, if no other handler is already registered. If there is already a registered handler, they MAY prompt the user to change it once when they first run the client.
 | |
| 
 | |
| === BNF grammar ===
 | |
| 
 | |
| (See also [[#Simpler syntax|a simpler representation of syntax]])
 | |
| 
 | |
|  bitcoinurn      = "bitcoin:" bitcoinaddress [ ";version=" bitcoinversion ] [ "?" bitcoinparams ]
 | |
|  bitcoinaddress  = base58 *base58
 | |
|  bitcoinversion  = "1.0"
 | |
|  bitcoinparams   = *bitcoinparam
 | |
|  bitcoinparam    = amountparam | labelparam | messageparam | sendparam | otherparam
 | |
|  amountparam     = "amount=" amount
 | |
|  amount          = amountdecimal | amounthex
 | |
|  amountdecimal   = *digit [ "." *digit ] [ "X" *digit ]
 | |
|  amounthex       = "x" *hexdigit [ "." *hexdigit ] [ "X" *hexdigit ]
 | |
|  labelparam      = "label=" *pchar
 | |
|  messageparam    = "message=" *pchar
 | |
|  sendparam       = "send=" *pchar
 | |
|  otherparam      = pchar *pchar "=" *pchar
 | |
| 
 | |
| === Query Keys ===
 | |
| 
 | |
| *label: Label for that address (e.g. name of receiver)
 | |
| *address: bitcoin address
 | |
| *message: message that shown to the user after scanning the QR code
 | |
| *size: amount of base bitcoin units ([[#Transfer amount/size|see below]])
 | |
| *send: used to send bitcoin, rather than to request them
 | |
| *(others): optional, for future extensions
 | |
| 
 | |
| ==== Transfer amount/size ====
 | |
| 
 | |
| If an amount is provided, it may be specified either in decimal or, when prefixed with a single "x" character, hexadecimal.
 | |
| The number SHOULD be followed by "X" <digits> to signify an exponent to the base multiplier.
 | |
| Thus, "X8" multiplies your number by 100,000,000.
 | |
| For decimal values, this means the standard BTC unit.
 | |
| For hexadecimal values, this means ᵇTBC units (which are equivalent to 42.94967296 BTC).
 | |
| If exponent is omitted, implementations SHOULD assume X8 for decimal numbers, and X4 for hexadecimal numbers.
 | |
| I.e. amount=50.00 is treated as 50 BTC, and amount=x40 is treated as 40 TBC.
 | |
| When specifying bitcoin base units, "X0" SHOULD be used.
 | |
| 
 | |
| Bitcoin clients MAY display the amount in any format that is not intended to deceive the user.
 | |
| They SHOULD choose a format that is foremost least confusing, and only after that most reasonable given the amount requested.
 | |
| For example, so long as the majority of users work in BTC units, values should always be displayed in BTC by default, even if mBTC or TBC would otherwise be a more logical interpretation of the amount.
 | |
| 
 | |
| == Rationale ==
 | |
| 
 | |
| ===Payment identifiers, not person identifiers===
 | |
| Current best practices are that a unique address should be used for every transaction.
 | |
| Therefore, a URI scheme should not represent an exchange of personal information, but a one-time payment.
 | |
| 
 | |
| ===Accessibility (URI scheme name)===
 | |
| Should someone from the outside happen to see such a URI, the URI scheme name already gives a description.
 | |
| A quick search should then do the rest to help them find the resources needed to make their payment.
 | |
| Other proposed names sound much more cryptic; the chance that someone googles that out of curiosity are much slimmer.
 | |
| Also, very likely, what he will find are mostly technical specifications - not the best introduction to bitcoin.
 | |
| 
 | |
| ==Forward compatibility==
 | |
| We want URIs generated in 2011 to still work in 2036: think about extensibility.
 | |
| Of course we can make only educated guesses about the future, but don't act as if there is none.
 | |
| This should be the best we can do, but it should not be seen as set in stone.
 | |
| Make it possible for later generations to improve our work, to mend our errors, without breaking the URIs created now.
 | |
| 
 | |
| == Appendix ==
 | |
| 
 | |
| === Simpler syntax ===
 | |
| 
 | |
| This section is non-normative and does not cover all possible syntax.
 | |
| Please see the [[#BNF grammar|BNF grammar]] above for the normative syntax.
 | |
| 
 | |
| [foo] means optional, <bar> are placeholders
 | |
| 
 | |
| <pre>
 | |
|  bitcoin:<address>[;version=1.0][?amount=<amount>][?label=<label>][?message=<message>][?send=<private key>]
 | |
| </pre>
 | |
| 
 | |
| === Examples ===
 | |
| 
 | |
| Just the address:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L
 | |
| 
 | |
| Address with name:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?label=Luke-Jr
 | |
| 
 | |
| Request 20.30 BTC to "Luke-Jr":
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=20.3X8&label=Luke-Jr
 | |
| 
 | |
| Request 400 TBC:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=x400X4
 | |
| 
 | |
| Request 4000 TBC:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=x4X7
 | |
| 
 | |
| Request 5 uBTC:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=5X2
 | |
| 
 | |
| Request 50 BTC with message:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=50X8&label=Luke-Jr&message=Donation%20for%20project%20xyz
 | |
| 
 | |
| Send 1 BTC:
 | |
|  bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=1X8&send=S4b3N3oGqDqR5jNuxEvDwf
 | |
| 
 | |
| Characters must be URI encoded properly.
 | |
| 
 | |
| ===Sending money via private key===
 | |
| To send a payment to someone else first construct a new keypair. You may want to use a [[mini private key format]], or you may also use a full private key for more security depending on the amount being sent and how long you expect to pass before a claim. Now create and publish a transaction with an output of the amount you wish to send. Use this script in that output:
 | |
| 
 | |
| <pre>
 | |
|  <pubkey> OP_CHECKSIG
 | |
| </pre>
 | |
| 
 | |
| Construct an address from the public key. Encode the URI as below:
 | |
| 
 | |
| <pre>
 | |
|  bitcoin:<address>?send=<base 58 encoded private key>
 | |
| </pre>
 | |
| 
 | |
| You may optionally include amount or message fields as well. In a wallet to claim money sent this way search for an incoming transaction with the output script form above, where <address> matches the public key in the script. When you find the transaction create a claim transaction with an input script of this form:
 | |
| 
 | |
| <pre>
 | |
|  <sig>
 | |
| </pre>
 | |
| 
 | |
| This claims the money you were sent. Until your claim transaction has confirmed the sender may take their money back.
 | |
| 
 | |
| == Reference Implementations ==
 | |
| === Bitcoin clients ===
 | |
| * [[Spesmilo]] supports all valid Bitcoin URIs, with Windows and KDE integration
 | |
| 
 | |
| === Parsing amount ===
 | |
| ==== ECMAScript ====
 | |
| <pre>
 | |
|  reAmount = /^(([\d.]+)(X(\d+))?|x([\da-f]*)(\.([\da-f]*))?(X([\da-f]+))?)$/i;
 | |
|  function parseAmount(txt) {
 | |
|     var m = txt.match(reAmount);
 | |
|     return m[5] ? (
 | |
|         (
 | |
|             parseInt(m[5], 16) +
 | |
|             (m[7] ? (parseInt(m[7], 16) * Math.pow(16, -(m[7].length))) : 0)
 | |
|         ) * (
 | |
|             m[9] ? Math.pow(16, parseInt(m[9], 16)) : 0x10000
 | |
|         )
 | |
|     ) : (
 | |
|             m[2]
 | |
|         *
 | |
|             (m[4] ? Math.pow(10, m[4]) : 1e8)
 | |
|     );
 | |
|  }
 | |
| </pre>
 | |
| 
 | |
| ==== Python ====
 | |
| <pre>
 | |
|  m = re.match(r'^(([\d.]+)(X(\d+))?|x([\da-f]*)(\.([\da-f]*))?(X([\da-f]+))?)$', amount, re.IGNORECASE)
 | |
|  if m.group(5):
 | |
|      amount = float(int(m.group(5), 16))
 | |
|      if m.group(7):
 | |
|          amount += float(int(m.group(7), 16)) * pow(16, -(len(m.group(7))))
 | |
|      if m.group(9):
 | |
|          amount *= pow(16, int(m.group(9), 16))
 | |
|      else:
 | |
|          amount *= 0x10000
 | |
|  else:
 | |
|      amount = Decimal(m.group(2))
 | |
|      if m.group(4):
 | |
|          amount *= 10 ** int(m.group(4))
 | |
|      else:
 | |
|          amount *= 100000000
 | |
| </pre>
 | |
| 
 | |
| ==== C# ====
 | |
| <pre>
 | |
|  Regex amountExpression = new Regex(@"^(([\d.]+)(X(\d+))?|x([\da-f]*)(\.([\da-f]*))?(X([\da-f]+))?)$", RegexOptions.IgnoreCase);
 | |
|  Match match = amountExpression.Match(value);
 | |
|  if (match.Success)
 | |
|  {
 | |
|      if (match.Groups[5].Success)
 | |
|      {
 | |
|          long hexDecimal = 0;
 | |
|          if (match.Groups[7].Success)
 | |
|              hexDecimal = Convert.ToInt64(match.Groups[7].Value, 16) * (long)Math.Pow(16, -match.Groups[7].Length);
 | |
| 
 | |
|          long hexExponent = 0x10000;
 | |
|          if (match.Groups[9].Success)
 | |
|              hexExponent = (long)Math.Pow(16, Convert.ToInt32(match.Groups[9].Value, 16));
 | |
| 
 | |
|          Amount = (Convert.ToInt64(match.Groups[5].Value, 16) + hexDecimal) * hexExponent;
 | |
|      }
 | |
|      else
 | |
|      {
 | |
|          long decimalExponent = 100000000;
 | |
|          if (match.Groups[4].Success)
 | |
|              decimalExponent = (long)Math.Pow(10, int.Parse(match.Groups[4].Value));
 | |
|          Amount = (long)(decimal.Parse(match.Groups[2].Value) * decimalExponent);
 | |
|      }
 | |
|  }
 | |
| </pre>
 |