Greetings!
We’ve been thinking how we can improve Ethereum developer experience and one of the pain points we came across is interaction with Web3 providers.
We would love to receive feedback on that proposal from the community, especially from @mortimr, @asselstine, @ianbrtt, @scammi, @paulinablaszk, @rstormsf, @obernardovieira!
Web3 Provider API
this product is for Ethereum Developers
who need an easy and reliable way to manage Web3 providers
this implementation hides various providers behind common API
that provides one line access to Web3 Provider API
unlike web3-react, embark.js
this solution doesn’t force you to use other libs
Why?
The current state of Web3 Providers is a wild combination of various EIPS (1474, 1193, 1102), libraries (web3.js, ethers.js, metamask, truffle), clients (geth, parity, ganache) and transport layers (HTTP, web sockets, IPC). Given the possibility of almost any combination of the mentioned factors, it is absolutely impossible to predict the outcome for a particular project. Some combinations wouldn’t even run but rather just throw a straight error on a start.
What do Ethereum application developers need from Web3 provider?
Surprisingly most Ethereum developers have quite common needs:
- Get data from Ethereum blockchain
- Send transactions
- React on network changed, account change and other events
- There are other niche requirements but they can be handled given the first three satisfied and working instance of Web3 library is provided.
Challenges
Does current provider support events (accountsChanged, networkChanged)?
It depends on a library, for example, web3.js@1.0.0-beta.37 which is used a lot doesn’t support these events. Some clients don’t support WebSockets. HttpProvider will never support it due to the nature of HTTP and considered depreciated, yet despite all of this it is the most widely mentioned and popular Web3 provider. In short, it is impossible to answer precisely and the most likely answer right now is no.
Can current provider sign and send transaction?
Is it Infura? Then no. Is it Metamask? If it is unlocked and the user will sign then yes. Is it Geth? If accounts unlocked then yes. From a JS layer, it is impossible to say will the current provider sign a transaction. Even more, there is no guarantee that the next transaction will be signed even if previous was successful. Geth can be locked down by timeout for example.
Are we connected to the Ethereum right now?
Not only some providers like HttpProvider not capable of notifying connectivity loss but in many cases they can die silent – forceful termination of a node, disabling Metamask extension. It is crucial for reliable and delightful developer experience to notify on connection loss as soon as possible.
Solution
Given current situation in tech stack surrounding Web3 providers, we have to provide the solution to maximize reliability and consistency while minimizing dependency on particular implementations.
interface Web3Context {
connected: boolean,
accounts: string[],
networkId: number,
lib: any,
onAccountsChanged(callback: (accounts: string[]) => void);
onNetworkChanged(callback: (networkId: number) => void);
onConnectionChanged(callback: (connected: boolean) => void);
}
connected
Returns true if connected to Ethereum node
accounts
Returns a list of accounts.
networkId
Returns a network id of a currently connected network.
lib
Returns instance of web3.js set up with the current provider.
onAccountsChanged
Fires every time accounts change.
onNetworkChanged
Fires every time a network change.
onConnectionChanged
Fires if a connection is established or lost.
Implementation Details
Events onAccountsChanged and onNetworkChanged picked because they satisfy all the requirements with minimal API and compliant with EIP 1193.
Behind the scene, Web3Context wouldn’t rely on EIP 1193 to receive such events from a Web3 provider because it might be not be available and the only Web3 provider to support it fully seems to be Metamask. Instead of that Web3Context will use a 100 milliseconds poll to query for much more reliable eth_accounts
and net_version
functions from EIP 1474 and update the state, fire events based on that. The approach also resolves the loss of a connection issue.
Web3Context would also call ethereum.enable
if it detects window.ethereum instance presence according to the EIP 1102.
Getting Web3Context
function getInjectedWeb3(): Web3Context
function getNetworkWeb3(connection: string): Web3Context
You either get Web3Context from an injected provider like Metamask or you are connected using a provider like Infura. For a start, we’ll leverage web3.js to create providers based on a connection string but if needed we can create our own providers or wrap existing.
What next?
Create helper functions for React to injected and manage our Web3Context
Update ZepKit with Web3Context
GSN network support