--- eip: 4804 title: Web3 URL to EVM Call Message Translation description: A translation of an HTTP-style Web3 URL to an EVM call message author: Qi Zhou (@qizhou), Chao Pi (@pichaoqkc), Sam Wilson (@SamWilsn) discussions-to: https://ethereum-magicians.org/t/eip-4804-web3-url-to-evm-call-message-translation/8300 status: Final type: Standards Track category: ERC created: 2022-02-14 requires: 137 --- ## Abstract This standard translates an RFC 2396 URI like `web3://uniswap.eth/` to an EVM message such as: ``` EVMMessage { To: 0xaabbccddee.... // where uniswap.eth's address registered at ENS Calldata: 0x ... } ``` ## Motivation Currently, reading data from Web3 generally relies on a translation done by a Web2 proxy to Web3 blockchain. The translation is mostly done by the proxies such as dApp websites/node service provider/etherscan, which are out of the control of users. The standard here aims to provide a simple way for Web2 users to directly access the content of Web3, especially on-chain Web contents such as SVG/HTML. Moreover, this standard enables interoperability with other standards already compatible with URIs, like SVG/HTML. ## Specification This specification only defines read-only (i.e. Solidity's `view` functions) semantics. State modifying functions may be defined as a future extension. A Web3 URL is in the following form ``` web3URL = web3Schema [userinfo "@"] contractName [":" chainid] path ["?" query] web3Schema = [ "ethereum-web3://" | "eth-web3://" | "web3://" ] contractName = address | [name "." [ subDomain0 "." ... ]] nsProviderSuffix path = ["/" method ["/" argument_0 ["/" argument_1 ... ]]] argument = [type "!"] value query = "attribute_1=value_1 [ "&" attribute_2=value_2 ... ] attribute = "returns" | "returnTypes" | other_attribute ``` where - **web3Schema** indicates the schema of the URL, which is `web3://` or `w3://` for short. - **userinfo** indicates which user is calling the EVM, i.e., "From" field in EVM call message. If not specified, the protocol will use 0x0 as the sender address. - **contractName** indicates the contract to be called, i.e., "To" field in the EVM call message. If the **contractName** is an **address**, i.e., 0x + 20-byte-data hex, then "To" will be the address. Otherwise, the name is from a name service. In the second case, **nsProviderSuffix** will be the suffix from name service providers such as "eth", etc. The way to translate the name from a name service to an address will be discussed in later EIPs. - **chainid** indicates which chain to resolve **contractName** and call the message. If not specified, the protocol will use the same chain as the name service provider, e.g., 1 for eth. If no name service provider is available, the default chainid is 1. - **query** is an optional component containing a sequence of attribute-value pairs separated by "&". ### Resolve Mode Once the "To" address and chainid are determined, the protocol will check the resolver mode of contract by calling "resolveMode" method. The protocol currently supports two resolve modes: #### Manual Mode The manual mode will not do any interpretation of **path** and **query**, and put **path** [ "?" **query** ] as the calldata of the message directly. #### Auto Mode The auto mode is the default mode to resolve (also applies when the "resolveMode" method is unavailable in the target contract). In the auto mode, if **path** is empty, then the protocol will call the target contract with empty calldata. Otherwise, the calldata of the EVM message will use standard Solidity contract ABI, where - **method** is a string of function method be called - **argument_i** is the ith argument of the method. If **type** is specified, the value will be translated to the corresponding type. The protocol currently supports the basic types such as uint256, bytes32, address, bytes, and string. If **type** is not specified, then the type will be automatically detected using the following rule in a sequential way: 1. **type**="uint256", if **value** is numeric; or 2. **type**="bytes32", if **value** is in the form of 0x+32-byte-data hex; or 3. **type**="address", if **value** is in the form of 0x+20-byte-data hex; or 4. **type**="bytes", if **value** is in the form of 0x followed by any number of bytes besides 20 or 32; or 5. else **type**="address" and parse the argument as a domain name in the form of `[name "." [ subDomain0 "." ... ]] nsProviderSuffix`. In this case, the actual value of the argument will be obtained from **nsProviderSuffix**, e.g., eth. If **nsProviderSuffix** is not supported, an unsupported NS provider error will be returned. Note that if **method** does not exist, i.e., **path** is empty or "/", then the contract will be called with empty calldata. - **returns** attribute in **query** tells the format of the returned data. If not specified, the returned message data will be parsed in "(bytes32)" and MIME will be set based on the suffix of the last argument. If **returns** is "()", the returned data will be parsed in raw bytes in JSON. Otherwise, the returned message will be parsed in the specified **returns** attribute in JSON. If multiple **returns** attributes are present, the value of the last **returns** attribute will be applied. Note that **returnTypes** is the alias of **returns**, but it is not recommended to use and is mainly for backward-compatible purpose. ### Examples #### Example 1 ``` web3://w3url.eth/ ``` The protocol will find the address of **w3url.eth** from ENS in chainid 1 (Mainnet), and then the protocol will call the address with "From" = "0x..." and "Calldata" = "0x2F". #### Example 2 ``` web3://cyberbrokers-meta.eth/renderBroker/9999 ``` The protocol will find the address of **cyberbrokers-meta.eth** from ENS on chainid 1 (Mainnet), and then call the address with "To" = "0x..." and "Calldata" = "0x" + `keccak("view(uint256)")[0:4] + abi.encode(uint256(9999))`. #### Example 3 ``` web3://vitalikblog.eth:5/ ``` The protocol will find the address of **vitalikblog.eth** from ENS on chainid 5 (Goerli), and then call the address with "From" = "0x..." and "Calldata" = "0x2F" with chainid = 5. #### Example 4 ``` web3://0xe4ba0e245436b737468c206ab5c8f4950597ab7f:42170/ ``` The protocol will call the address with "To" = "0x9e081Df45E0D167636DB9C61C7ce719A58d82E3b" and "Calldata" = "0x" with chainid = 42170 (Arbitrum Nova). #### Example 5 ``` web3://0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/balanceOf/vitalik.eth?returns=(uint256) ``` The protocol will find the addresses of **vitalik.eth** from ENS on chainid 1 (Mainnet) and then call the method "balanceOf(address)" of the contract with the **charles.eth**'s address. The returned data will be parsed as uint256 like `[ "10000000000000" ]`. #### Example 6 ``` web3://0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/balanceOf/vitalik.eth?returns=() ``` The protocol will find the address of **vitalik.eth** from ENS on chainid 1 (Mainnet) and then call the method "balanceOf(address)" of the address. The returned data will be parsed as raw bytes like `["0x000000000000000000000000000000000000000000000000000009184e72a000"]`. ## Rationale The purpose of the proposal is to add a decentralized presentation layer for Ethereum. With the layer, we are able to render any web content (including HTML/CSS/JPG/PNG/SVG, etc) on-chain using human-readable URLs, and thus EVM can be served as decentralized Backend. The design of the standard is based on the following principles: - **Human-readable**. The Web3 URL should be easily recognized by human similar to Web2 URL (`http://`). As a result, we support names from name services to replace address for better readability. In addition, instead of using calldata in hex, we use human-readable method + arguments and translate them to calldata for better readability. - **Maximum-Compatible with HTTP-URL standard**. The Web3 URL should be compatible with HTTP-URL standard including relative pathing, query, fragment, etc so that the support of existing HTTP-URL (e.g., by browser) can be easily extended to Web3 URL with minimal modification. This also means that existing Web2 users can easily migrate to Web3 with minimal extra knowledge of this standard. - **Simple**. Instead of providing explicit types in arguments, we use a "maximum likelihood" principle of auto-detecting the types of the arguments such as address, bytes32, and uint256. This could greatly minimize the length of URL, while avoiding confusion. In addition, explicit types are also supported to clear the confusion if necessary. - **Flexible**. The contract is able to override the encoding rule so that the contract has fine-control of understanding the actual Web resources that the users want to locate. ## Security Considerations No security considerations were found. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).