EIP-4804: Web3 URL to EVM Call Message Translation

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:


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:
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

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.

Hi everyone. We have launched two gateways w3eth.io and w3link.io to support the standard.

We have uploaded all @VitalikButerin’s blog (40MB) on Arbitrum Nova mainnet permanently with only 0.13 ETH! Using the standard and gateway, you can browse the unstoppable website at https://0xe4ba0e245436b737468c206ab5c8f4950597ab7f.arb-nova.w3link.io/ or with ENS https://vitalikblog.w3eth.io (or web3://vitalikblog.eth/) !

1 Like


Just discovered this EIP, nice!
I’ve been developping a electron-based proof-of-concept browser implementing a evm:// protocol I made up (&& refined with frolic), so I am happy to migrate to this EIP.

I have several questions :

  • Auto mode: If I have a method that returns 3 strings, and I want the second one returned as string, not JSON, how do I do it? For example, a method that return a token representation in HTML, SVG, TXT(ascii art) that I put in . For tuples and non-bytes/string results, I feel there should be a way to say that we want the result either as raw or as json?
  • Auto mode: If I have a method that returns a string and I want to return this string cast as a specific MIME type (e.g. image/svg+xml), how do I do it?
  • Auto mode: If I have a mathod that returns returns 2 variables, and I want the second one cast as image/svg+xml ?
  • Auto mode: Autodetection of the type of argument : I can see an issue with the autodetection of bytes : if the contract expect bytes, and we put bytes in the URL and don’t explicitely set the type, and by bad luck it has 20 or 32 length, then autodetection switch to bytes32/address type and the call signature changes, and it breaks the call. So maybe, for the bytes type, the type must always be explicitely present, it should not be autodetectable, like string?
  • Manual mode: how do you specify the return data types and MIME type, since the full path?query is sent to the smartcontract?


1 Like

If my understanding is correct, you can put returns=(string, string, string) in the query, and the standard will return the JSON like [s0, s1, s2], and then you can retrieve the second one by getting s1 in the JSON data. E.g.,

curl web3://contractAddr/method?returns=(string,string,string) | jq '.[1]'
(you may replace web3:// with a gateway)
Then it should return the second string as you need.

Thanks for the comment. The easiest way is to allow the contract to accept the argument as string + “.” + suffix, where the suffix will decide the MIME return type. You can check the description of the standard here:

An example of such a link is here

Thanks for the comment. I don’t think you can do that as MIME can be only applied to one web3:// response (and it should also apply to an HTTP:// response). In such a case, you should separate the returned variables into two different methods.

Thanks for the comment. The reason to support autodetection for address and bytes32 is that they are much more frequently used vs other non-20-or-32 bytes on contracts. I do see a potential problem that a developer/user may put a bytes with auto-detection but it was mistakenly parsed to address or bytes32. One way is that we can remove the auto-detection for non-20-or-32 bytes so that for bytes input, we always ask for explicit bytes type. We can collect more consensus from the community on this part.

Thanks for the comment. It will be determined by the last argument of the full path. See below copied from the standard.

It is a bit confusing that the MIME detection only applies to “auto” model, but it actually applies to both “auto” and “manual” modes.

Hope this could explain. Thank you!

Thank you for your answers!

Ok, yes the usecase I had in mind was, what if I want to directly access the value because I am using for example <img src="web3://..." />,…
But yes this usecase should be very very rare, and if it happens, one can always write a method proxying this. So I drop this.

Ok so if I understand correctly, in your example, the actual web3 url would be : web3://0x804a6b66b071e7e6494ae0e03768a536ded64262/compose/string!111.svg
I can see a problem : Let’s take
What if I wanted to send the string “bla.svg” as argument to the method? So here I don’t want to cast the result as SVG, I just want to send the string “bla.svg”.
So if a method ask for a string, and by bad luck, there is at the end of the string a dot and some letters, and the browser recognized these letters as a mime type, then the browser would remove the dot and the letters from the argument given to the method, and the browser would wrongly cast the output as something not planned.
Maybe an idea would be to put the (still optional) mime suffix to the method, web3://<contract>/<method>[.<suffix>]/<arg1>... such as web3://0xxxxxx/method.html/string!bla.svg ?

Ok for mime type.
Regarding the return data types, is it mandatory on the manual mode that a method must return only one value, or can it returns multiple values, and we have to declare it with returns=() ?

Thank you for your answers :slight_smile:

Thanks for the comments. If the string happens to be the last argument with a suffix, it may return an undesired MIME. However, I would guess such a situation will be rare for auto mode. In the manual mode, since the contract developer already knows EIP-4804, the MIME with the last argument with a suffix should fall into the contract design expectation (i.e., the developer should avoid passing “.svg” as the last argument to a non-svg data).

The key thing is that the auto mode is designed to be compatible with existing contracts, which are not aware of EIP-4804, and thus we should not rely on any assumption on the method name. If the contract uses manual mode, then the contract developer should be aware of EIP-4804, and thus the developer could design the way to work with MIME detection correctly. What do you think?

In the long term, we may add the third mode (or an option to manual mode) to support the MIME return by contracts. That means each contract method in this method will return (bytes32, bytes32), where the first one is the MIME type, and the second one is the data. Or we may even support a mode that each method will return (httpResponseHeader, bytes32). However, this seems to be a rather big change, we need to collect more comments from the community, especially experts from HTTP or browsers.

Thanks for the comment. The manual mode is designed for the contracts designed for the frontend, so it only returns one value (bytes32) and declares it with returns=() will just pass the data to calldata.

In the future, we may add the reserved queries that may be prefixed by __ (double underscore) if we want to pass more other info such as gasLimit, but we may need to collect more consensus from the community to see if it is the best way.

Thank for the answer.

Ok for auto mode : we can say that when we develop a website, and we want to call a external third-party method that could trigger this bug, we can write a wrapper around it.
So I will focus on manual mode :

I think it is too bad that, when I develop an onchain website, I will always need to think that there should be not dots in the last argument of my URLs.

My string arguments would either need to not be the last argument of URLs, or need to not contains dots. If the string is provided by user, I would need to replace dots by another placeholder.
And I just realized that even float numbers have this issue :


(unfortunately “.123” is a valid mime type of application/vnd.lotus-1-2-3)
So if I want to make a method that takes as input only a float, I would need to add a dummy argument at the end, or replace dots by a placeholder, or scale them by 10^n to avoid the dot.

Would it not be better to do it in a way that does not add constraints on the contents of your arguments when you develop a onchain website?

If you think it is not a problem, I will say no more and I will implement the browser using the current EIP-4804 definition.

That’s great to hear :slight_smile: I also have some ideas for a third mode, but yeah let’s keep that for later.

Thanks for the comment. With the float or with dots in argument, I think an easy is to add the suffix to tell what type it is. E.g., for web3://xxxx/method_using_gps_coordinautes/36.214/23.123, if you want to return an SVG file, then you can have the URL as


This will allow the system to quickly identify the MIME to return.

Note that, in manual mode, we may not expect to have method in the path (while auto mode will always have) since all path+query will be sent to the contract as the calldata. Taking Vitalik’s blog as an example, the following is a valid web3:// URL


where index.html is just the path of the file (i.e., calldata=‘/index.hml’).

Hope this could explain. Thank you!

Thanks for the reply!
Ok got it: if there is the possibility of a dot in the last argument, always add the extension.
I will now work to implement web3:// on the evm-browser.

1 Like

I think I should post it here too :
Here is an proof of concept implementation of eip-4804, with support of proposed EIP-6821 for domain name resolution:

Only limitation : web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies) are disabled (very indirectly due to chromium URL parser not liking hexadecimal numbers as a host of an URL)

1 Like

Fantastic work! Looking forward to the full support!

ERC-4804: Web3 URL to EVM Call Message Translation with @qizhou

1 Like

Many thanks for organizing and hosting the interview!

1 Like

I’m happy to have found this EIP; it’s an idea I was thinking should be created, and glad to see that it’s had great progress made!

As an artist and developer, I’m keenly interested in the image/SVG handling. Sounds like handling of URLs ending in .svg is in progress but not quite implemented yet? From my experience exploring existing smart contracts that do on-chain image-generation, for string or bytes returns, there’s a few ways they format the results:

The “Raw String” style would need a suffix on it in the Web3 URL, or would have to use some form of “magic bytes” processing to guess at the file format (which would likely have varying levels of success being automatic). Data-URL-formatted strings could be automatically unwound by the gateway server and have a good level of confidence in what format the output is supposed to be (for standard mediatypes). This would help many different output types, including text formats (e.g. Autoglyphs web3://0xd4e4078ca3495de5b1d4db434bebc5a986197782/draw/100)

The “Token URI” format is a special case that I’m not sure if the Web3 URL gateway wants to be able to support? In general it’s a question of if the gateway structure wants to be able to unwind JSON-structured results programmatically? If the request ends in “/100.json”, it’s clear the request is desiring JSON as a response. But if the request ends with “/100.svg”, but the smart contract returns a string that has a data URL prefix indicating it’s JSON, the gateway could parse the JSON, and return just the image property of the JSON object?

Or, to be more specific, the Web3 URL format could create a specific way to indicate a specific property of a JSON result is desired? Some possible URL formats for “sending argument ‘100’ results in a string output that is JSON-encoded. Grab the ‘image’ property of that JSON object and return it, formatted as an SVG”:

  • .../100.json/image.svg
  • .../100.json#image.svg
  • .../100.json?result=(image:image/svg+xml)

That first format treats JSON files as if they were folders in a file hierarchy, which seems to fit with the other goals of this initiative?

One other thing to consider is using the Accept HTTP header as a way to deduce the request’s intent, and also as a way to determine desired failback methods. A request that comes with a header of

Accept: image/svg+xml, application/json;q=0.9, text/html;q=0.8, */*;q=0.5

is then very clear that it desires SVG data primarily, but if the gateway cannot serve that, JSON is second-choice, followed by HTML, and it failing all that, it would accept any other format the gateway can serve. That behavior is less to do with the URL itself, so not sure if that should be part of this standard, or a different standard on gateway behavior? The “Accept HTTP Header” is usually described as part of how the http:// schema is defined, so in that case it would fit that it should be called out in this standard that defines the web3:// schema how it handles request headers, and not just the URL itself?

A method of string encoding that is promoted by the IPFS ecosystem (which many Ethereum projects use, but I haven’t seen any smart contracts use this style of string encoding in their output) is using a “Multibase” identifier.

Multibase as a protocol allows for specifying Base-64-encoding (“m” prefix), as well as JSON-formatted payload (Multicodec 0x0200 prefix), so could be another text format to auto-detect and parse.

1 Like

Regarding the “resolve modes” for this standard, it currently looks to the resolveMode function to determine what the contract is capable of. Has there been any consideration done to include ERC165 as part of how a gateway determines what the contract is capable of? For widely-used standards like ERC20, ERC721, and ERC1155, if a contract presents an ERC165 interface that advertises it supports one of those standards, that could help make more robust “default” responses?

For example, if a request is made for a contract with no function call in the path, and the gateway tries calling a resolveMode function and it returns “auto”, it could then try calling a supportsInterface function on that contract, and if it returns true for ERC20, then the gateway could return an HTML “card” representation of that contract’s name, symbol, and total supply (the known static metadata options for ERC20 contracts).

This could also affect not just the default return for a contract, but for contracts like ERC721, could make a call like web3://collectionaddress/100 return an HTML representation of token ID 100 from that NFT collection (showing image, properties, current owner, etc.)

Would there be any interest in having “auto” mode be “smarter” by using ERC165 interfaces?