Skip to content

Latest commit

 

History

History
105 lines (76 loc) · 7 KB

File metadata and controls

105 lines (76 loc) · 7 KB

Wallet Integration

Any wallet available in a browser environment can integrate into Mask Network. Well know wallets like MetaMask, WalletConnect and Fortmatic have already been integrated. Besides that, Mask Network is also able to host accounts by itself.

Overview

   Front End Page                                 Background Page
+------------------+                            +-----------------+
|       User       | - Messaging API ---------- |  RPC Composer   |
+------------------+                            +-----------------+
                                                |                 |
+------------------+                   +-----------------+   +-----------------+
| Bridge Component | - Event Emitter-- |  Other Wallets  |   |   Mask Wallet   |
+------------------+                   +-----------------+   +-----------------+
         |                                                            |
+------------------+                                                  |
|    Wallet SDK    |                                                  |
+------------------+                                                  |
         |                                                            |
         +------------------------- Network --------------------------+

Above is an architecture overview illustrating how Mask Network integrates multiple wallets simultaneously. Roughly speaking, it includes two parts: the bridge component on the front end, and the JSON-RPC composer on the background end. They communicate with each other by leveraging the Messaging Passing API.

As a quick example to let you know how all stuff spins. Here is a UI button that will emit an eth_getBlockNumber request once it is clicked.

import { useWeb3 } from '@masknet/web3-shared-evm'

function Example() {
  const web3 = useWeb3()
  const onClick = useCallback(async () => {
    const blockNumber = await web3.eth.getBlockNumber()
    console.log(`The current block number is ${blockNumber}.`)
  }, [web3])
  return <button onClick={onClick}>Get Block Number</button>
}

First of all, it creates a Web3 instance which redirects all JSON-RPC requests to the request service on the background page. If you'd like to read the source code, you will realise that there is a Koa.js styled composer built-in. A list of middleware is used and serve different purposes: a middleware stores transactions into DB, a middleware watches transaction status, a middleware notifies transaction progress, and so on.

At the current stage, there are two kinds of wallets: Mask Wallet and other wallets.

Mask Wallet sends requests to the network directly on the background page. If the request takes the response, then the user will get notified.

But it's not that simple for other wallets. They are supported only on the front end. E.g., the Fortmatic SDK injects an iframe on the currently visiting page. Mask Network cannot invoke those SDKs on the background page as an extension. Because of that, they should take their requests to the front end and handle them there. Many mounted components, so-called ProviderBridge, listen to the PROVIDER_RPC_REQUEST event and call the corresponding SDK once they receive any request from the background. After the SKD finishes the work, they return the result to the bridged provider on the background page with the PROVIDER_RPC_RESPONSE event.

It takes a quite long detour, but the benefit is all requests can leverage Mask Wallet abilities.

A Wallet on a bridged provider

If the wallet that only works on the front end. It needs to use the bridged provider way.

On the front end:

On the background page:

A wallet without any UI

If the wallet is totally UI free and can connect/disconnect by calling some APIs. It can send requests to those APIs directly.

On the background page:

Interceptor

The implementation of Ethereum JSON-RPC may very different between wallets. Those JSON-RPC requests will need some preprocessing before sending to the real wallet. Nevertheless, the Mask Network flavors a bunch of self-known RPC methods that were unknown to other wallets. Bypassing a such request will hit an unimplemented error.

For this sake, the composer creates a middleware for intercepting JSON-RPC requests. Here is a quick example that converts the Mask Network flavored mask_requestAccounts into an Ethereum styled eth_accounts.

export class Example implements Middleware<Context> {
  async fn(context: Context, next: () => Promise<void>) {
    switch (context.method) {
      case EthereumMethodType.MASK_REQUEST_ACCOUNTS:
        context.requestArguments = {
          ...context.requestArguments,
          method: EthereumMethodType.ETH_ACCOUNTS,
        }
        break
      default:
        break
    }
    await next()
  }
}

Examples

Wallet Implementation
MetaMask -
WalletConnect -
Fortmatic -