ERC-4804 Converting a Web3 URL to an EVM call (Web3 URL to EVM Call Message Translation)
Final · Names & metadata · created 2022-02-14
These are the rules for turning a web address such as web3://uniswap.eth/ into a read call to an Ethereum contract. With a human-readable URL like a browser address, you can reach on-chain content directly.
Why it is needed
Today, reading Web3 data mostly depends on a Web2 proxy that translates requests toward the blockchain. Intermediary services such as dApp websites, node service providers and Etherscan handle that conversion, and they are outside the user's control. Even when web content such as SVG or HTML is stored on chain, ordinary users had no way to retrieve it directly without an intermediary. In addition, existing web standards identify their targets with a URI (an address string that points to a resource), but an Ethereum contract call is expressed as hexadecimal calldata, so there was no common format to connect the two. This standard defines rules for converting an address starting with web3:// into an EVM call message, so that Web2 users can reach Web3 content directly and the standard can interoperate with other standards that use URIs.
In depth
Structure of a Web3 URL
A Web3 URL has the form web3Schema [userinfo "@"] contractName [":" chainid] path ["?" query]. web3Schema is one of ethereum-web3://, eth-web3://, or web3://, and the original text explains that it is written as web3:// or, in short, w3://. contractName is either a 20-byte address starting with 0x or a name of the form [name "." [subDomain0 "." ...]] nsProviderSuffix. path is ["/" method ["/" argument_0 ["/" argument_1 ...]]], where the method name and arguments are joined by slashes, and each argument can be prefixed with a type as [type "!"] value. query is attribute=value pairs joined by &, and the attribute can be returns, returnTypes or other attributes. This specification defines only read-only semantics corresponding to Solidity view functions, and leaves state-changing functions to later extensions.
Determining From, To and chainid of the call message
userinfo is the From field of the EVM call message, that is, who is making the call. If it is not specified, the sender address is 0x0. contractName is the To field. If it is an address written as 0x followed by 20 bytes of hex, that value is used as To. Otherwise it is treated as a name service name, and the provider matching nsProviderSuffix (for example eth) is asked for the address. The source says the concrete method for converting a name to an address is covered in a later EIP. chainid is the chain on which contractName is resolved and the message is called. If it is not specified, the same chain as the name service provider is used, which is 1 for eth. If there is no name service provider, the default chainid is 1.
resolveMode and the two resolve modes
Once the To address and chainid are determined, the protocol calls the contract's resolveMode method to check the resolve mode. Two modes are currently supported. Manual Mode does not interpret path and query at all and puts the path ["?" query] string directly into the message calldata. It is used when a contract wants to define its own encoding rules. Auto Mode is the default and also applies when the target contract has no resolveMode method. In Auto Mode, if path is empty the call is made with empty calldata, and otherwise the calldata is built with the standard Solidity contract ABI. If there is no method, that is, if path is empty or "/", the call is also made with empty calldata.
Argument type inference rules in Auto Mode
In Auto Mode, method is the string name of the function to call and argument_i is the i-th argument of that function. If type is given, the value is converted to that type, and the basic types currently supported are uint256, bytes32, address, bytes, and string. If type is omitted, the type is detected automatically in this order. 1) If the value is a number, uint256. 2) If it is 0x followed by 32 bytes of hex, bytes32. 3) If it is 0x followed by 20 bytes of hex, address. 4) If it is 0x followed by a byte count other than 20 or 32, bytes. 5) Otherwise it is treated as an address, and the value is parsed as a domain name of the form [name "." [subDomain0 "." ...]] nsProviderSuffix. In case 5, the actual argument value is obtained from the name service for nsProviderSuffix (for example eth), and if the suffix is not supported, an unsupported NS provider error is returned. The source calls this approach the maximum likelihood principle and explains that it keeps URLs short while allowing any ambiguity to be resolved with an explicit type.
The returns attribute and interpreting return data
The returns attribute of query tells how to decode the return data. If it is not specified, the return data is parsed as (bytes32), and the MIME type is determined from the suffix (extension) of the last argument. If returns is (), the return data is put into the JSON as raw bytes. For any other value, it is parsed into JSON according to the specified returns type. If there are multiple returns attributes, the last one applies. returnTypes is an alias of returns that is kept for backward compatibility, so its use is not recommended. For example, balanceOf/vitalik.eth?returns=(uint256) returns the result as a uint256 value such as [ "10000000000000" ], and ?returns=() returns it as a byte string such as ["0x000000000000000000000000000000000000000000000000000009184e72a000"].
Resolution results from the source examples
web3://w3url.eth/ looks up the address of w3url.eth in ENS on chainid 1 (mainnet) and calls that address. web3://cyberbrokers-meta.eth/renderBroker/9999 finds the address the same way and then calls it with calldata that ABI-encodes the method name and the uint256 argument 9999. web3://vitalikblog.eth:5/ looks up the name in ENS on chainid 5 (Goerli) and calls on chainid 5. When an address is written directly, as in web3://0xe4ba0e245436b737468c206ab5c8f4950597ab7f:42170/, the name service is skipped and the call is made on chainid 42170 (Arbitrum Nova) with empty calldata. web3://0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/balanceOf/vitalik.eth converts the argument vitalik.eth to an address using ENS on chainid 1 according to rule 5, and then calls balanceOf(address).
Design principles and scope
The source Rationale describes the purpose of this proposal as adding a decentralized presentation layer to Ethereum. The idea is to render web content such as HTML, CSS, JPG, PNG, and SVG on chain through human-readable URLs and to use the EVM as a decentralized backend. There are four design principles. Human-readable: for easy recognition like http://, it uses name service names instead of addresses and methods and arguments instead of hex calldata. Maximum compatibility with HTTP URLs: it follows existing HTTP URL standards such as relative paths, queries, and fragments so that browsers and others can support it with small modifications. Simple: automatic argument type detection keeps URLs short. Flexible: contracts can override the encoding rules. This standard requires EIP-137 (requires: 137), and all examples use ENS as the name service. Its status is Final.