EIP-4804: Web3 URL to EVM Call Message Translation

Many thanks for your comments. A couple of my responses:

Nice! I have added the sentence Moreover, this standard enables interoperability with other standards already compatible with URIs, like SVG. in the motivation part.

Thanks for the comment. I feel that eth:// may be a bit narrow because the protocol itself can support any EVM blockchains such as Polygon/BSC or even testnets. For evm://, I feel it is a bit technical because a lot of Web2 people may not have an idea what EVM is.

I have been struggling to choose the best scheme name. I finally choose web3:// because the major goal of the protocol is to be the counterpart of http:// in Web2. Further, given the fact that Ethereum/EVM has been the de-facto Web3 technical stack, using web3:// could strengthen the position of Ethereum/EVM in Web3 without creating confusion. Feel free to let me know if you have other thoughts.

Thanks for the comment. The hashtag will be pre-processed by the browser so that the type info may not be passed to the gateway or web extension. If we want to process them on the client side, we need to return an HTML that processes the type info, which may be complicated. Instead, if we could process them on server side, then the user can browse the formatted result either in browser or curl/wget or programs easily.

Thanks for the comment. balanceOf should match method in the grammar:

Web3URL = "web3://" [userinfo "@"] contractName [":" chainid] ["->(" returnTypes ")"] path [? query]
contractName = address | name "." nsProvider
path = ["/" method ["/" argument_0 ["/" argument_1 ... ]]]
argument = [type "!"] value

As the result, the protocol will call “balanceOf(address)” with charles.eth's address from NS. Please let me know if I miss anything.

I agree that retrieving ABI definition is not easy in this case. Actually, mandating the types in the link still needs ABI definitions for implementers. So the cost should be the same no matter whether the types are mandatory or not.

The reason for providing auto-type detection is to make the URL as simple and natural as possible. Further, in our current gateway implementation, we will return web3-calldata, web3-method-siganture, and web3-return-type in HTTP response headers for better debuggability. The following is an example of

https://web3q.io/wusdt.eth:4->(uint256)/balanceOf/charles.eth

image

I would argue that http is pretty technical :rofl: I don’t feel too strongly about the actual prefix though.

Is the intent to resolve the URIs through a browser? Although it’s possible to return HTML directly from a contract, I don’t expect that to be too normal (or gas efficient.) If the anchor is stripped before passing to a web extension, then yeah, it wouldn’t make sense to put it there.

The only non-binary data I’m familiar with on-chain today would be NFT metadata/image data.

Ha, can’t believe I missed that… Obviously that makes sense.

I think if you had a URI like web3://foo.eth/balanceOf/address!bar.eth that would be sufficient to call the function. Actually, you could even do web3://foo.eth/balanceOf(address):uint256/bar.eth. What am I missing?

Are the types in the current EIP are there to disambiguate between overrides?


On an unrelated note:

In the second case, nsProvider will be the short name of name service providers such as “ens”, “w3q”, etc.

This seems to imply that an ENS lookup would have to be web3://foo.eth.ens/... or web3://example.com.ens/...? The examples later in the EIP don’t match that pattern.

Thanks for the comment. The intention is to resolve the URIs via a gateway (like ipfs.io) or a web browser extension. The browser just passes the full Web3 URI to the gateway/extension, and the gateway/extension would have full knowledge to parse the URIs to EVM call message and format the returned data back to the browser via HTTP protocol. This requires minimal changes on browsers so that we can use any browser (Chrome/Firefox/IE/etc) to browse Web3 URIs easily.

The standard would perfectly fit into NFT metadata/image data like SVG (I am also a big fan of it :slight_smile: ). Meanwhile, we are exploring other non-binary data such as dWeb or even dynamic Web page generation (decentralized social network?). There are a lot of possibilities here enabled by Ethereum and ERC-4804!

Many thanks for the comment. A couple of great design questions for the standard. Let me list them one-by-one:

Q1: For address from name service, should we use name type or address type? E.g.,

  • web3://foo.eth/balanceOf/address!bar.eth ; or
  • web3://foo.eth/balanceOf/name!bar.eth?

Using address type for both conventional 0x-20-bytes-hex ETH address space and name from NS should work as ETH address will never have “.”, but should we separate these types for better clarification?

Q2: Do we need type auto-detection, i.e., do we need the simpler URI at the price of potential ambiguity? E.g.,

  • web3://foo.eth/balanceOf/address!bar.eth
  • web3://foo.eth/balanceOf/bar.eth
    where the first is with mandatory type and the second’s type is auto-detected.

Actually, auto-detection may coexist with manual resolve mode better. Taking a dWeb as an example, the user may type (myhome.eth is in manual resolve mode)

  • web3://myhome.eth/aaa.svg,

which will pass /aaa.svg as the calldata so that the contract can display the file directly. As a comparison, using the mandatory typed link in auto resolve mode will look like

  • web3://myhome.eth/showFile/string!aaa.svg
    which is more verbose.

Q3: If types are supplied, where to put the input argument types and return types (which can be a tuple)? E.g.,

  1. web3://foo.eth/balanceOf(address):(uint256)/bar.eth
  2. web3://foo.eth/balanceOf(address)->(uint256)/bar.eth
  3. web3://foo.eth/balanceOf->(uint256)/address!bar.eth
  4. web3://foo.eth->(uint256)/balanceOf/address!bar.eth

I personally prefer “->” to prepend return types as it is clear to understand. In addition, current standard puts “->(outputTypes)” after the contract name (Option 4) so that the path part of the link looks almost the same as that of the Web2 HTTP link. Admittedly, Option 1 or 2 is closer to what current Solidity has, but seems to be incompatible with auto-detection for types.

Nice find! I have changed the sentence to

In the second case, nsProviderSuffix will be the suffix from name service providers such as “eth”, “w3q”, etc.

If you’re using a gateway (like foo.test), I’m guessing the full URL would look something like https://example.eth.foo.test/balanceOf/bar.eth#uint256? If the gateway is returning the raw data, it wouldn’t be able to access the anchor… So it makes sense to put it in the path component.

If we want everything to be symmetric, then it makes sense to put it in the path for extensions and direct requests too. You’ve convinced me :slight_smile:

I guess the reverse question is also important: will there ever be a NS provider without a .? I have a slight preference for just using address, but that mandates a dot in the name. Small trade-off, in my opinion.

I totally overlooked the section on auto-detection. I don’t think the contract being queried should be able to affect the interpretation of the URI. That would mean I’d need to know what mode the contract is in to correctly construct a URI, which would make autogeneration of URIs (say in on-chain SVGs) difficult.

I’d most prefer an explicitly typed URI, but it might be possible to make some unambiguous rules to infer types.

Yeah, looking at your examples, I like -> more too. Doing name(type arg0)->(type,type) will be pretty familiar to Rust devs :wink:

I definitely don’t think it should come before the first /. If it does, it looks like part of the “host”.

Just kinda throwing the idea out, but what if there were some implied defaults, if not specified? For example web3://foo.eth/->/aaa.svg could mean "call a function with the signature index(string) -> (string)".


How would you handle resolving ENS names that use DNSSEC? For example supersaiyan.xyz is a valid ENS name.

We also had an internal discussion on which one is better, but no strong preference. I think we could choose address now by assuming that all NS providers must have “.”.

Thanks for the comment. I would argue a potential huge application with “manual” mode for on-chain Web content generation. To be more specific, the current standard serves two major purposes:

Purpose 1: Call a contract for JSON-formated result

If the returned types are specified, the protocol will
1. call the contract;
2. get the call result in raw bytes;
3. parse the raw bytes into ABI-encoded types as specified by returned types;
4. format the ABI-encoded types to JSON and return the JSON response to the client.
This can be viewed as a complement to the existing JSON-RPC protocol.

Purpose 2: Call a contract for on-chain Web content

If the returned types are not specified, the protocol will assume that an on-chain web content (e.g., HTML/SVG/CSS/etc) will be returned to the client. This is perhaps the most attractive application of the standard.

My original design for this purpose comes from common gateway interface (CGI) - the famous interface for Web servers. In CGI, the web server allows its owner to configure which URLs should be handled by which CGI scripts. For example,

http://example.com/cgi-bin/printenv.pl/with/additional/path?and=a&query=string

this will ask web server to call printenv.pl script with /with/additional/path?and=a&query=string as argument.

With manual resolve mode, the smart contract can work as CGI script similar to Web2. This brings the following unique benefits:

  • Support Web3 URI with HTTP-URL-style path and query, which existing Web2 users are most familiar with;
  • Be compatible with existing HTTP-URL pathing, such as relative path. This means a HTML/XML can reference their relative resources easily (e.g., web3://aaa.eth/a.svg referencing ./layers/0.svg will be translated to web3://aaa.eth/layers/0.svg by browser);
  • Default web index (e.g., web3://aaa.eth/ could reference to web3://aaa.eth/index.html as configured by the contract).

I think that these features should greatly bridge the gap between Web2 users to Web3 dApps.

Admittedly that the users need to know what mode the contract is in to correctly construct a URI. However, the manual mode only works to CGI contracts that serve special web content needs, while 99+% of existing contracts are not affected. As a result, we could safely assume that the implementers (most likely the CGI contract developers) have the full knowledge of how to interact with CGI contracts in manual model.

What do you think?

I think if we enable manual mode, the implied defaults may be implemented by the contract themselves? Similar to setting directory index in Web servers (Web server directory index)

Thanks for the comment. Do not have a plan right now. But we could create an extension EIP for supporting DNSSEC after finalizing this one?

Some updates on EIP-4804

  1. name type is replaced by address type
  2. add a principle to highlight that EIP-4804 should be maximum compatible with the HTTP-URL standard so that existing Web2 users can migrate to Web3 easily with minimal knowledge of this standard.

The second one is inspired by our discussion of interoperability with SVG (or more generally, any on-chain Web content), which is one of the most applications we want to support. Please take a look.

Yes, the URL may look like
https://example.eth.foo.test/balanceOf/bar.eth#uint256 or
https://foo.test/example.eth/balanceOf/bar.eth#uint256

where the ipfs’s gateway has similar link to resolve ipfs resources.

Given the principle that we want to maximize compatibility with HTTP-URL, we the 5th option may be
5. web3://foo.eth/balanceOf/address!bar.eth?returnType=(uint256)

which is more like a standard HTTP-URL.

An illustration of auto mode and manual mode for resolving web3 URLs

2 Likes

EIP has been merged yesterday Create EIP-4804 (#4995) · ethereum/EIPs@49fc53b · GitHub

2 Likes

hey sers, i’m thinking about implementing this as a web2.0 service, would love to dm and talk about it. my telegram is @monkeyontheloose

Hey peeps, I believe I found a similar technique and proposed it to standardize in CASA: eth_call signature combined with block number is a unique identifier · Issue #87 · ChainAgnostic/CAIPs · GitHub

Thanks for pointing this out. Looks like there are a couple of overlaps, but it seems the target applications are quite different? E.g., ERC-4804 serves as an HTTP-style resource locator, which is designed with some unique features

  • MIME detection
  • Auto-type detection to simplify the links
  • CGI-style resolve model to allow “smart contract as CGI script”
  • Do not ask for the block number (but we could add it if we really need this)

A couple of applications are

BTW: Our extension for supporting web3:// links is available at Firefox Web3Q: Fully Decentralized Web3 – Get this Extension for 🦊 Firefox (en-US)

We discussed this proposal in today’s CASA meeting:

  • According to RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax, the URI scheme namespace is managed by https://www.iana.org/ and so we think it is out of the scope of this proposal to use “web3://” (unless you’re planning to register it there or we’ve missed something).
  • As Ethereum is just one chain within “web3,” we noted that a potentially better scheme identifier for this EIP would be “eth://” or e.g. “evm://”
  • From what I understood, CASA would be happy to welcome this EIP on their side as to e.g. generalize the scheme towards “web3://” (multi-chain)
1 Like

Similar discussion wrt the uri identifier is being discussed by @SamWilsn and the in draft webRTC connection for web3 providers.

Chrome blocks non standard uri identifiers as well

1 Like

Many thanks for the information. The assignment information is very helpful. I just send a request for assigning web3:// schema of URI for EIP-4804 to iana and wait for their response :slight_smile: I will update the info if I get any response.

Thanks for the comment. EIP-4804 natively supports multiple EVM chains (i.e., rinkeby/kovan/arbi/optim/bsc by replacing port to chain id) so I feel using eth:// may be too narrow. Further, one major application of EIP-4804 is to provide a web3 resource locator that can be dynamically generated on-chain, especially web resources such as SVG/HTML, therefore I feel that web3:// may better serve the purpose.

Many thanks for the invitation. I am very glad to explore the applications of web3:// for non-EVM blockchains, and I am open to collaborating on the generalization and improving EIP-4804 accordingly. For the next step, one thing I would like to do is to give a presentation of the motivation, design thoughts, and applications of EIP-4804 at the next CASA meeting? Then we could collect some consensus and move to future steps. What do you think?

Just let everyone know that we have registered web3:// URI scheme at IANA. Anyone can find the assignment at Uniform Resource Identifier (URI) Schemes :raised_hands:

2 Likes

How does gateway resolution work if I don’t specify a gateway like foo.test?

Is there any proof returned in the response to make sure that my gateway is not lying to me?

nice EIP.

what I would suggest is to encode the entire signature at once like so:
web3://.../balanceOf(address)/...
since the entire canonical signature is used to encode the function selector. an error in parsing arguments (e.g. confusing bytes32/uint256, or bool/uint8/uint256 or bytes/strings, etc.) could lead to incorrect function called.
if there’s a fallback that behaves differently it would be unintuitive to debug.

by specifying the exact function signature then you don’t have ambiguities with params and can leave params out as defaults. (e.g. balanceOf(address) with no param would be balanceOf(0x0))

once you have the function 4bytes selector you can fetch the return type from a db such as 4bytes.directory.

edit: if I may suggest it can be useful to pass an optional block number too, eg. in case you want to fetch balance in a previous block.

Generally, to avoid lying to the users, the browser needs to

  1. become a light client of the blockchain (in the Ethereum PoW chain case, that means all headers, which need some time to download.)
  2. show the proof of data visited. This is mostly the Merkle proof of the data in the state trie.

Note that asking the gateway to return these data for each web3:// request (especially all headers) may be over-burdened.

To achieve a fully trustless web, one direction is to have a browser extension that

  1. becomes a light client of the blockchain, which downloads the headers in the background (can from the gateway or p2p network); and
  2. ask the gateway to respond with the proof (or the extension itself can directly access p2p network). With the light client data, we can tell whether the gateway lies or not.

There are a lot of interesting things that need to be done, but I think the web3 URL will serve as a good starting point to enable a fully-decentralized web3!

We have a discussion on where to put the argument types in the standard here EIP-4804: Web3 URL to EVM Call Message Translation - #13 by qizhou, where I think your suggestion is close to option 2
image

We have a regular URI/URL meeting every two weeks. In the last meeting, we reached the agreement to use returnTypes attribute to specify the return types. I could include the topic of where to specify the input types in the next meeting (see here for more info URL/URI standard working group - HackMD)

This seems to introduce the dependency on 3rd party db. I think we should avoid this because the standard is a decentralized resource locator that should not depend on any 3rd component.

This can be done by setting an optional block attribute in the attribute-value list. However, we may not expect the gateway or browser to fully support it because calling a contract on a historical block requires running an archive node.

Hey, I’ve added the block number tag to CAIP-19:

Would be cool if this EIP also included it such that we can link to any historical chain state.