EIP-681 — ethereum: transaction-request URIs (summary)¶
A condensed reference for the part of EIP-681 cuere implements in
ethereum_uri and erc20_transfer_uri. It is a
summary, not the spec — read the original for anything load-bearing.
Grammar¶
request = "ethereum" ":" [ "pay-" ] target_address
[ "@" chain_id ] [ "/" function_name ] [ "?" parameters ]
target_address = ethereum_address ; "0x" + 40 hex digits, or an ENS name
chain_id = 1*DIGIT ; EIP-155 network id, e.g. 1 = mainnet
function_name = STRING ; e.g. "transfer"
parameters = parameter *( "&" parameter )
parameter = key "=" value
key = "value" | "gas" | "gasLimit" | "gasPrice" | TYPE
value = number | ethereum_address | STRING
number = [ "-" | "+" ] *DIGIT [ "." 1*DIGIT ]
[ ( "e" | "E" ) [ 1*DIGIT ] [ "+" UNIT ] ]
Two shapes matter here:
- Native payment — no function name; the
valueparameter is the amount of ether to send, in wei (1 ETH = 10¹⁸ wei):ethereum:0xADDR?value=…. - Contract call — a
function_nameplus typed arguments. The canonical ERC-20 case istransfer(address,uint256):ethereum:0xTOKEN/transfer?address=0xRECIPIENT&uint256=AMOUNT. The argument keys are the Solidity types (address,uint256);AMOUNTis in the token's own base units (itsdecimals).
chain_id (when present) sits between the address and the /function
path, so a chain-scoped transfer is ethereum:0xTOKEN@1/transfer?…. The
optional pay- prefix marks an explicit payment; cuere omits it, emitting the
bare ethereum:0x… form that wallets accept most broadly.
EIP-681's number grammar allows scientific notation with a unit suffix (e.g.
value=2.014e18). cuere instead emits a plain integer number of wei, which
every wallet parses unambiguously.
EIP-55 — address checksums are case-significant¶
An Ethereum address is 20 bytes shown as 0x + 40 hex digits. EIP-55 mixes
the case of the a–f hex letters to encode a keccak-256 checksum, so
0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359 and its all-lowercase form are the
same address but only the former carries the checksum. Consequences for cuere:
- An
ethereum:URI is byte-mode and case-significant: it must be stored and rendered verbatim, never upper/lower-cased. optimize_uritherefore refuses theethereum:scheme outright — uppercasing it to reach QR-alphanumeric mode (as it does for bech32bitcoin:/lightning:; see bip-21.md) would corrupt the checksum. Never pass anethereum:URI throughoptimize_uri.
What cuere does¶
ethereum_uri(address, *, value=None, chain_id=None, gas_limit=None, gas_price=None)builds the native-payment form.erc20_transfer_uri(token, *, to, amount, chain_id=None, gas_limit=None, gas_price=None)builds thetransfer(address,uint256)form.
Shared rules:
- Addresses (
address,token,to) are validated structurally as0x+ 40 hex digits with case preserved. This is not an EIP-55 checksum verification — that needs keccak-256, a crypto dependency cuere intentionally does not bundle (the same stancebitcoin_uritakes on base58check). value,gas_price, and the ERC-20amountareuint256words (acceptint/ base-10str/ integralDecimal); they must be whole and in the fulluint256range0 … 2²⁵⁶−1—0is accepted, since it is the EVM word's natural default and EIP-681 imposes no positivity (unlike a BIP-21amount, which must be positive).value/gas_priceare in wei;amountis in the token's base units (cuere does not know a token'sdecimals, so it applies no scaling).gas_limitandchain_idare likewise non-negative integers.boolis rejected even though it is anintsubtype.- Gas is emitted as the
gasLimit/gasPricekeys; cuere does not emit thegasabbreviation that EIP-681 treats as a synonym forgasLimit. - The result is a plain
strthat composes withrender/show.
Out of scope (candidate follow-ups): the pay- prefix, ENS-name targets,
arbitrary function_name calls beyond ERC-20 transfer, the gas synonym, and
scientific-notation value output.