ERC-681 Transaction request URL format (URL Format for Transaction Requests)
Final · Accounts & wallets · created 2017-08-01
A standard for writing a payment request for ether or ERC-20 tokens as a single URL line beginning with ethereum:. When it is delivered in a QR code or link, the user's wallet app opens with the recipient address and amount pre-filled.
Why it is needed
When asking someone to send ether, if the 40-character recipient address and the amount are given separately, the user has to copy them into the wallet by hand. If even one character of the address is wrong, the money goes to the wrong place. If the amount unit is wrong, the magnitude is off. Token payments are more complicated. The token contract address, the recipient address and the quantity must all be entered correctly. The source explains that the convenience of writing payment requests as a standard URL played a large part in Bitcoin spreading widely as a payment method. Ethereum had no such common format, so each app had to send and receive requests in a different way. The earlier ERC-67 was a format that represented arbitrary transactions at a low level, and it has already fallen out of use. This standard takes over that role, focusing on the most common case of payment requests while also allowing requests for other function calls defined by an ABI.
In depth
URL syntax
The URL begins with ethereum:, which may be followed by the optional prefix pay-. Next come the target address (target_address), optionally followed by @ and a chain ID (chain_id), / and a function name (function_name), and ? and parameters (parameters). The source ABNF is request = schema_prefix target_address [ "@" chain_id ] [ "/" function_name ] [ "?" parameters ]. The address is either 0x followed by 40 hexadecimal digits or an ENS name from ERC-137. The chain ID is a decimal number. The function name and string values (STRING) are URL-encoded Unicode strings, and delimiter characters and the % sign must be hex-encoded with a % prefix. Future revisions that are not compatible with this proposal, even partially, must use a prefix other than pay-, separated by a dash (-) character.
Parameter keys and number notation
Parameters are key=value pairs joined with &. The key is one of value, gas, gasLimit or gasPrice, or an ABI type name (TYPE). If the key is value, gasLimit, gasPrice or gas, the value must be a number, and otherwise it must be a value that fits the ABI type used as the key. A number consists of a sign, digits, a decimal point, and an exponent after e or E. The exponent means a multiple by a power of 10, so 2.014e18 is 2.014 times 10 to the 18th power. Because only integers are allowed, the exponent must be greater than or equal to the number of digits after the decimal point. The source strongly recommends scientific notation when writing amounts, and says that for readability the exponent should match 18 for ether, and for ERC-20 tokens the value returned by the token contract's decimals().
Target address, chain ID, ENS priority
target_address is required. It is either the recipient of a native token payment or the address of the contract the user will interact with. chain_id is optional and holds a decimal chain ID, so a request can also target a transaction on a testnet or private network. If it is omitted, the client's current network setting applies as is. If an ENS name is used, resolving it is the payer's responsibility and can be done at any time from when the URL is received until the transaction is sent. A hexadecimal address always takes precedence over an ENS name. Even if an ENS name consisting of 0x followed by 40 hexadecimal characters actually exists, it must never be resolved and the value must be used directly as a hexadecimal address. The 0x prefix follows convention, and it also clearly distinguishes a hexadecimal address from an ENS name made of 40 alphanumeric characters.
Ether payment request
If function_name is absent, the URL requests a payment in the blockchain's native token, that is, ether. The amount goes in the value parameter in the smallest unit (wei). The source's example is ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18, which requests 2.014 ETH to the address 0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359. Fixing the exponent at 18 makes the number before the decimal point equal to the amount in ETH, which is easy for people to read. An ether payment request that contains only the recipient address is also compatible with the earlier standard, ERC-67.
ERC-20 token payment request
A token payment takes the form of a request to call the token contract's transfer function. Put the token contract address in target_address and set function_name to transfer. Then pass the recipient address in the address-type parameter and the quantity in the smallest unit in the uint256-type parameter. The source's example is ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1, which requests 1 Unicorn token to the address 0x8e23ee67d1332ad560396262c48ffbb01f93d052. Payment requests are the main use case, but the same approach can request other function calls defined by an ABI.
Amount and gas are suggested values
The amount in the URL is only a suggestion, and so are the other arguments. The user is free to change them. If the amount is absent, the wallet must ask the user to enter the amount to send. gasLimit and gasPrice are likewise suggested values for the gas limit and gas price, and the user can edit them. gasLimit can be abbreviated to gas, and the two are treated as having the same meaning. The source states that more parameters can be added if widely used use cases actually appear.
Why it was made to resemble the Bitcoin URL
The format was chosen to be as close as possible to the bitcoin: URL that users and developers already know. That is also why the unit notation commonly used in the Ethereum ecosystem was omitted. The difference in magnitude is handled with an exponent, so that an amount can be written in nominal units as with bitcoin:. The delivery paths are also broad. According to the source, on Android a URL carried in a broadcast intent is the main way to launch an app, and desktop browsers have a standard way to define a protocol handler for a given scheme. Other desktop apps usually open a browser when they encounter a URL. As a result, a payment request URL can be delivered through many channels, such as QR codes, web links, email, and chat messages.
Things to watch out for
- Origin and integrity of the URL: Because the URL's parameters start an irreversible transaction, the integrity and authenticity of the URL are critically important. An attack that profits from merely changing the recipient address or the amount is possible. Users should use only URLs received from an authenticated source and sufficiently protected against tampering.
- Payment hijacking through ENS: To prevent attacks that redirect a payment elsewhere through ENS, the hexadecimal interpretation of an Ethereum address must take precedence over an ENS lookup. If an ENS name looks visually similar to a hexadecimal address, the client may warn the user, or it may treat the name as likely phishing and reject it outright.
- Amount display and digit checking: So that the amount actually sent equals the intended amount, the amount shown to the user must be easy to check by eye, down to the number of digits. For an ERC-20 token payment, if the wallet can look up the token contract on the blockchain or from a trusted source, it must display the amount in the unit defined in the contract. If it cannot, it may show the amount as written in the URL but notify the user that the nominal unit is uncertain. To make human checking easier, scientific notation with the exponent matched to the token's nominal unit (18 for ether) is recommended.