Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Supporting ETH-like Networks #3604

Closed
derekchiang opened this issue Mar 17, 2018 · 21 comments
Closed

RFC: Supporting ETH-like Networks #3604

derekchiang opened this issue Mar 17, 2018 · 21 comments
Labels

Comments

@derekchiang
Copy link

Abstract

In an ideal world, MetaMask would support every chain. In practice, a lot of these chains have very different properties and semantics which makes supporting all of them very difficult from both a technical and a UX perspective. See #2532 for an example of a proposal towards solving this problem.

At the same time, there are chains that are very similar, if not outright the same as, Ethereum. Examples of such chains include POA.network and Thunder. These chains should in theory be very easy to support, and in fact MetaMask already provides a "Custom RPC" option where the user may enter a URL that points to a node that exposes the Ethereum JSON RPC.

Using the custom RPC option is however less than ideal, since it requires the user to manually input the URL, which is not only inconvenient but also leaves room for human errors and attacks.

This RFC describes a protocol wherein the dapp may declare the chains it prefers to use and provide any parameters necessary, thus saving the user from having to manually provide the parameters.

Definition

Here we define an ETH-like chain as a chain that exposes the Ethereum JSON RPC. Examples of such chains include POA. network and Thunder.

Overview

As we know, MetaMask injects a web3 object into the JS context. We add a function setPreferredNetworks to the web3 object.

// Ensure that the code doesn't break in a non-MetaMask environment
if (typeof web3.setPreferredNetworks === 'function') {
  web3.setPreferredNetworks(CHAIN_ID1, CHAIN_ID2, CHAIN_OPTS3...)
}

setPreferredNetworks accepts a variable number of parameters, each of which specifies either a chain ID or a chain options object.

A chain ID is exactly as defined in EIP 155. It's an integer that identifies a chain. MetaMask will internally maintain a registry of well-known chains such as the Ethereum mainnet, Ropsten, Rinkeby, etc. That way the dapp doesn't need to provide URLs for the most widely used chains.

For all other chains that MetaMask may not know about, they are specified with a chain options object.

The chain options object has the following properties:

  • name: a human-readable name of the chain. The MetaMask UI may display this name as appropriate.
  • chainID: the chain ID as described in EIP 155.
  • rpc: the RPC endpoint that MetaMask should use.

Example

if (typeof web3.setPreferredNetworks === 'function') {
  web3.setPreferredNetworks(
    1,  // Ethereum mainnet
    2,  // Rinkeby
    {
      name: "SomeCustomNetwork",
      chainID: 99,
      rpc: "https://rpc.somecustomnetwork.io"
    }
  )
}

UI

If setPreferredNetwork has been invoked, MetaMask displays an additional dropdown alongside the networks dropdown:

capture3

Here is how the expanded dropdown looks like:

capture4

The networks are displayed in the order that the caller specifies. The check indicates the network that's currently being used. Clicking on a network sets it as the currently used network.

Future work

It's likely that we might want to support more chain options. For instance, displaying the USD/ETH conversion rate may not make sense for every chain. But I wanted to put up this RFC first to get some initial feedback.

@derekchiang
Copy link
Author

@Zanibas yeah 100% agree that we should merge them into one dropdown, while making it clear which ones are the officially supported networks and which ones are custom networks.

Could you elaborate a bit on what sort of refactoring/restructuring needs to be done for this RFC to be implemented? That way contributors who are not necessarily familiar with MetaMask's codebase (such as myself) can know where to start.

@derekchiang

This comment has been minimized.

@rstormsf
Copy link

I love the idea of setting a preferredNetwork. @danfinlay what do you think?

@danfinlay
Copy link
Contributor

This is a nice proposal, thanks @derekchiang!

With our current architecture, one site requesting one network would change the network for every site, and that's obviously not what we want, so I think we should want to support multiple simultaneous networks at once first, which I've now opened an issue for as #3663.

That issue itself requires having per-domain configuration within MetaMask, and this happens to fit very neatly with our latest thinking on how to improve privacy by ensuring users log in explicitly to each domain (#714). I've just updated that proposal for the sake of referencing it here, so you can see that our current designs involve a type of sign-in request whose format could be neatly extended to include network information, like you're asking for here, which is a nice intermediary step on the road to #2532.

Thoughts on that?

@aldoborrero
Copy link

aldoborrero commented Mar 22, 2018

I would love to see this happening as I'm currently maintaining a fork of MetaMask for Ubiq (ours is called [Sparrow](https://github.com/ubiq/sparrow-extension)).

Personally, I would subscribe to @lazaridiscom has said of merging in only one place the preferred Network and the network selector.

But I would propose a different way of doing it:

Maybe we can think as creating a dashboard like where in the first step we show the icon of the Network (being Ethereum its logo, Poa.Network its logo, Ubiq its logo and so on), and after the user selects that, inside there's the list of the Networks supported by that network.

screen shot 2018-03-22 at 23 19 57

Something like above image but being each icon the logo of the Network.

Edit: Also as side note we can provide information for making MetaMask brandeable (so each Network could change it's brand colors, so the user would see easily by the color on which Network it is).

My 2 cents

@derekchiang
Copy link
Author

@aldoborrero I like your idea. I would imagine that most ETH-like networks have multiple testnets and a mainnet so it seems like a good idea to somehow group them together.

So presumably the dapp itself would provide the logo of the network or a link to the logo?


@danfinlay thanks for laying out the blockers. It did not occur to me that switching to a new network would affect dapps running on other tabs as well.

On a related note, what do you think if we have a registry like metamask/networks, and alt-chains can register by submitting PRs? Each PR would just be a simple configuration file that specifies the network name, the URL, the icon, etc. These networks would then be displayed in a menu like the one that @aldoborrero described.

The obvious downside is that now the MetaMask team has to review & approve the PRs. Though I'd imagine that these PRs would be very simple and there would normally be no reason to reject them.

Now that I think about it, it'd be fun to build such a registry on the blockchain itself...

@aldoborrero
Copy link

aldoborrero commented Mar 23, 2018

Yeah, I believe the way to go is to create a repository of metamask/networks as you correctly suggested @derekchiang .

For me, a Network plugin would provide its own metadata like the icons, the different networks they support (mainnet, testnet ...), the color branding (if that applies), which versions of MetaMask support (to allow api changes) and also a proper way to format the request and to parse it before being returned back to MetaMask.

For example, with Sparrow we're using Shokku (which is an open source Infura like clone) and it provides its own MetaMask provider for doing network calls.

In summary, each Network plugin should be an eth-json-rpc-infura on steroids.

In that way MetaMask guys only have to accept PR that meets certain criteria to be included in the plugin itself (or we can give access to the user to download and install new Network plugins).

@aldoborrero
Copy link

Yeah, sounds right to me @lazaridiscom

@derekchiang, @danfinlay @rstormsf (and whoever wants to join) maybe we should coordinate ourselves and align our expectations to provide such MVF .

@derekchiang
Copy link
Author

Hi guys, I dug into relevant issues including #714, #3383 and #3663. Here's my understanding of what needs to happen before MetaMask can support different networks:

  • Stop injecting web3 by default. Rather, let the dapp explicitly request metamask login as described here and here. See here for how backward compatibility with existing dapps can be maintained.

  • Refactor the "backend" code which handles connections with RPC providers such as Infura. The goal is to make it so that we can maintain connections with more than one RPC providers (e.g. Infura, POA, Thunder, etc.) at the same time.

  • Refactor the internal representation of accounts so that each account is associated with one and only one network. So unlike today, if account 0xabc is used for the ETH mainnet, then you can't use it for the Rinkeby testnet. This involves redesigning the UI too since currently you can switch networks while staying on the same account.

  • Redesign the account import / creation flow so that you also specify which network the account is supposed to be used with.

  • Implement the API (i.e. setPreferredNetwork) similar to what's proposed in this issue. Then, on the account selection screen (as proposed here), highlight the accounts from the preferred networks.

@aldoborrero @rstormsf @danfinlay @lazaridiscom does this general roadmap sound about right?

@danfinlay
Copy link
Contributor

That is one way of grouping it together, @derekchiang, I tend to like to keep the individual deliverables separate as possible, to allow incremental delivery.

Since you've included the each account is associated with one and only one network requirement into your list, I would emphasize that also this means users need a way to "recover" accounts that they previously used for multiple networks.

Also, I personally prefer the current #714 postMessage API over the setPreferredNetwork API from this issue, particularly because we're talking about not exposing web3 by default, and so we will probably allow the app to specify the network it prefers at the time that it requests web3, making that method unnecessary.

Other than that, I think that's a decent summary of what needs to be done.

@rstormsf
Copy link

Refactor the internal representation of accounts so that each account is associated with one and only one network. So unlike today, if account 0xabc is used for the ETH mainnet, then you can't use it for the Rinkeby testnet. This involves redesigning the UI too since currently you can switch networks while staying on the same account.

any reason for this one? it would increase the complexity of the account management.
I think you want to use different HD path for the seed wallet for each different network like MEW/Ledger/Trezor does, correct?

@derekchiang
Copy link
Author

@danfinlay ah right 100% agree. The postMessage API should be used for declaring preferred networks as well.


@rstormsf maybe I'm missing something, but without associating each account with a specific network, how would you filter accounts based on preferred networks? See this proposal. I was thinking that the dapp would declare the preferred networks (using postMessage), and then in the "Account Selection Popup" step (the third step), we'd highlight the accounts associated with the preferred networks.

Though I do agree that using the same seed but different HD path for each network sounds like a good idea. I'm just not sure how that works with the other proposals.

@danfinlay
Copy link
Contributor

Since there's a brief detour in the conversation, towards isolating accounts per network, I think I should also mention the @benjamincburns proposal to require a distinct secret per network: #3131

That one has specific benefits for people shifting between test and real networks, but for users shifting between multiple real networks, I think using distinct BIP39 paths might be enough.

@wighawag
Copy link

The proposal is interesting. I had a completely different one in mind where we could add a web3 method to request metamask to connect to it and metamask would show a popup confirming the switch

Regarding the proposal outlined here, I would like to add one thing :

Allowing the dapp to set a name is dangerous since this could be maliciously used to let the user believe it is connected to a alternative network while it is connected to the mainnet for example.

Metamask could check the network id if it is a known one and generate an error on dapps that tries to use a name for it.

@derekchiang
Copy link
Author

@danfinlay thanks for sharing #3131. It does look very relevant but like you wrote in the issue, storing a different secret per network would require a major overhaul.

Having re-read all the comments/issues a couple times and looked deeper into BIP39/44, I think this is probably our common ground right now:

  • MetaMask stores a "root" seed phrase, just like it does today.
  • A dapp uses postMessage to find MetaMask. It may optionally include a "network spec" which specifies 1) the RPC URL of the network and 2) the HD coin type of the network.
  • MetaMask prompts the user to unlock the wallet. It then displays an account selection screen like this.
  • Note that each account displayed is specific to the network. So if I click the text Main Network, I will see a dropdown and I can select a different network (say POA), then I will see a different list of accounts specifically for POA. This is because the account addresses were computed using the HD coin type of the network according to BIP39. Note that ETH mainnet and testnets share the same coin type, so switching between mainnet and testnet does not affect the displayed accounts.
  • If a network spec was specified, then the account selection screen first displays that network, though a different network can still be selected if the user so wishes.

@wighawag agreed that that's a problem. Another solution is to show a distinct color/image for each network (which MetaMask already does today). So for instance the Ethereum mainnet is always a green square.

@danfinlay
Copy link
Contributor

I mostly agree, @derekchiang, although I hadn't yet seen the idea of the postMessage specifying a coin type. This is probably fine, but I want to leave it out there for a bit before fully agreeing to that part, to see if I or anyone else can find a problem with that.

@jooray
Copy link

jooray commented Aug 14, 2018

I would like to be able to specify coin name and decimals. For example Rootstock uses SBTC tokens which are pegged to BTC. Showing transaction in "ETH" would be very confusing to users.

@hackmod
Copy link
Contributor

hackmod commented Aug 14, 2018

Please see #4932 this is currently working multi-chain support PR 😃

@bdresser
Copy link
Contributor

See also #5101

@NicolasMassart
Copy link

NicolasMassart commented Sep 19, 2018

I'm not fond of restricting an account to one network because it's the nice thing about accounts is that they can be used on any network.

However, transaction list should be bound to the network as today whatever the network you see all transactions for an account, which doesn't mean anything as a tx exist only on one network.

@Gudahtt
Copy link
Member

Gudahtt commented Jan 6, 2021

We have supported ETH-like networks that have a JSON-RPC endpoint for some time now via our "Custom RPC" functionality. I believe this meets the basic request outlined here, though it's quite different from the many proposals in this thread.

Switching networks programmatically and allowing the dapp to suggest/specify a network isn't supported yet, but I think progress toward that is best tracked under #5101. There are a few ideas in this thread not represented by #5101 either, but I think those would be best tracked under new tickets or in our Community Forum.

@Gudahtt Gudahtt closed this as completed Jan 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests