Skip to content

Instantly share code, notes, and snippets.

@nand2
Created September 29, 2023 10:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nand2/6f327cf2faf3957f80702eb19d28aad1 to your computer and use it in GitHub Desktop.
Save nand2/6f327cf2faf3957f80702eb19d28aad1 to your computer and use it in GitHub Desktop.
eip title description author discussions-to status type category created requires
6860
Web3 URL to EVM Call Message Translation
A translation of an HTTP-style Web3 URL to an EVM call message
Qi Zhou (@qizhou), Chao Pi (@pichaoqkc), Sam Wilson (@SamWilsn)
Draft
Standards Track
ERC
2023-09-29
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
   ...
}

⚠️ This proposal updates EIP-4804 with minor corrections, clarifications and additions.

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 the resolveMode method of the "To" address. The Solidity signature of resolveMode is:

function resolveMode() external returns (bytes32);

The protocol currently supports two resolve modes: auto and manual.

  • The manual mode will be used if the resolveMode return value is 0x6d616e75616c0000000000000000000000000000000000000000000000000000, i.e., "manual" in bytes32
  • The auto mode will be used if :
    • the resolveMode return value is 0x6175746f00000000000000000000000000000000000000000000000000000000, i.e, "auto" in bytes32
    • the resolveMode return value is 0x0000000000000000000000000000000000000000000000000000000000000000
    • the call to resolveMode throws an error (method not implemented of error thrown from the method)
  • Otherwise, the protocol will fail to the request with error "unsupported resolve mode".

Manual Mode

The manual mode will put path [ "?" query ] as calldata of the message directly. Path cannot be empty and must be at least /.

No interpretation of path and query will be done, except for the determination of MIME type based on a filename extension at the end of the path, if one is present :

path = path_part [ "." filename_extension ]

The returned message data will be treated as ABI-encoded bytes and the decoded bytes will be returned to the frontend.

Auto Mode

In the auto mode, if path is empty or "/", 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 these basic types: bool, int, uint, int<X>, uint<X> (with X ranging from 8 to 256 in steps of 8), address, bytes<X> (with X ranging from 1 to 32), 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.

    If type is "string", then value is URI-percent-encoded (RFC 3986) at least for the following characters: !, /, ?, %.

  • returns attribute in query tells the format of the returned data. Its value syntax is :

    value = ["(" [types] ")"]
    types = type_1 [ "," type_2 ... ]
    type = basic_type [ "[]" [ "[]" ... ]]
    

    basic_type can be any of the supported argument types.

    • If the returns attribute is undefined or empty, the returned message data will be treated as ABI-encoded bytes and the decoded bytes will be returned to the frontend.
    • If returns is equal to "()", this is an alias of "(bytes32)".
    • Otherwise, the returned message data will be ABI-decoded in the data types specified in the returns value and encoded in JSON format. 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.

The MIME will be set based on the suffix of the last argument or if there is no argument, the suffix of the method.

Examples

Example 1a

web3://w3url.eth/

where the contract of w3url.eth is in manual mode.

The protocol will find the address of w3url.eth from ENS in chainid 1 (Mainnet). Then the protocol will call the address with "Calldata" = keccak("resolveMode()")[0:4] = "0xDD473FAE", which returns "manual" in ABI-type "(bytes32)". After determining the manual mode of the contract, the protocol will call the address with "To" = contractAddress and "Calldata" = "0x2F". The returned data will be treated as ABI-type "(bytes)", and the decoded bytes will be returned to the frontend.

Example 1b

web3://w3url.eth/

where the contract of w3url.eth is in auto mode.

The protocol will find the address of w3url.eth from ENS in chainid 1 (Mainnet). Then the protocol will call the address with "Calldata" = keccak("resolveMode()")[0:4] = "0xDD473FAE", which returns "", i.e., the contract is in auto mode. After determining the auto mode of the contract, the protocol will call the address with "To" = contractAddress and "Calldata" = "". The returned data will be treated as ABI-type "(bytes)", and the decoded bytes will be returned to the frontend.

Example 2

web3://cyberbrokers-meta.eth/renderBroker/9999

where the contract of cyberbrokers-meta.eth is in auto mode.

The protocol will find the address of cyberbrokers-meta.eth from ENS on chainid 1 (Mainnet). Then the protocol will call the address with "Calldata" = keccak("resolveMode()")[0:4] = "0xDD473FAE", which returns "", i.e., the contract is in auto mode. After determining the auto mode of the contract, the protocol will call the address with "To" = contractAddress and "Calldata" = "0x" + keccak("renderBroker(uint256)")[0:4] + abi.encode(uint256(9999)). The returned data will be treated as ABI-type "(bytes)", and the decoded bytes will be returned to the frontend.

Example 3

web3://vitalikblog.eth:5/

where the contract of vitalikblog.eth:5 is in manual mode.

The protocol will find the address of vitalikblog.eth from ENS on chainid 5 (Goerli). Then after determing the contract is in manual mode, the protocol will call the address with "To" = contractAddress and "Calldata" = "0x2F" with chainid = 5. The returned data will be treated as ABI-type "(bytes)", and the decoded bytes will be returned to the frontend.

Example 4

web3://0xe4ba0e245436b737468c206ab5c8f4950597ab7f:42170/

where the contract "0xe4ba0e245436b737468c206ab5c8f4950597ab7f:42170" is in manual mode.

After determing the contract is in manual mode, the protocol will call the address with "To" = "0xe4ba0e245436b737468c206ab5c8f4950597ab7f" and "Calldata" = "0x2F" with chainid = 42170 (Arbitrum Nova). The returned data will be treated as ABI-type "(bytes)", and the decoded bytes will be returned to the frontend.

Example 5

web3://0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/balanceOf/vitalik.eth?returns=(uint256)

where the contract "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" is in auto mode.

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 vitalik.eth's address. The returned data from the call of the contract will be treated as ABI-type "(uint256)", and the decoded data will be returned to the frontend in JSON format like [ "10000000000000" ].

Example 6

web3://0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/balanceOf/vitalik.eth?returns=()

where the contract ”0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48“ is in auto mode.

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 from the call of the contract will be parsed as raw bytes in JSON format 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.

Changes versus ERC-4804

Corrections

  • Manual mode : ERC-4804 stipulates that there is no interpretation of the path [ "?" query ]. This ERC indicates that there is in fact an interpreation of the path : the determination of MIME type based on a filename extension at the end of the path, if one is present.
  • Auto mode : ERC-4804 stipulates that the returned data is parsed as ABI-encoded bytes32. This ERC indicates that in fact the returned data is parsed as ABI-encoded bytes.

Clarifications

  • Resolve mode: This ERC indicates more details on how the resolve mode is determined.
  • Auto mode : This ERC indicates in mode details the syntax of the returns value, and the fact that arrays are supported.
  • Examples : This ERC add more details to the examples.

Additions

  • Auto mode: Supported types: ERC-4804 supported only uint256, bytes32, address, bytes, and string. This ERC add more types.

Copyright

Copyright and related rights waived via CC0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment