How to Develop MetaMask Snaps

MetaMask is a cryptocurrency wallet for managing assets on Ethereum-like blockchains. It comes both as a browser extension and mobile application, and it is extremely popular among developers. Recently they introduced MetaMask Snaps, a way to extend the basic functionality.

Imagine how cool will be to interact with, for example, Bitcoin or Polkadot using MetaMask.

This technical blog post will explain how one can develop its extensions of the MetaMask wallet, called Snaps.

But first, what are Snaps?

Snaps are the Metamask Plugin System. MetaMask Snap is a program that one can run in an isolated environment that can customize the wallet experience.

Broadly speaking, MetaMask Snaps consists of two things:

  • a way to run untrusted JavaScript inside the MetaMask application 
  • APIs for websites and MetaMask to communicate with individual snaps

Snaps run in an isolated environment where they have access to limited capabilities, determined by the user’s permissions during installation. For example, a file-sharing plugin doesn’t need to know what page you’re on, just what hash you want to load or set.

As with MetaMask’s Ethereum JavaScript provider API, communication occurs via JSON-RPC requests and responses.

At present, snaps can make JSON-RPC requests of MetaMask, and websites can make JSON-RPC requests of MetaMask and snaps running inside MetaMask. In this way, Snaps can expand MetaMask’s RPC API and change the behavior of the MetaMask application at runtime.

Over time, MetaMask will use this to support different blockchain and other decentralized protocols, novel kinds of cryptography, crypto assets, and countless other features.

Snaps cannot modify the MetaMask UI for the prototype Snaps system but can extend the MetaMask RPC API and exchange arbitrary messages with websites visited by the user. Therefore, the user interface for any Snap must exist entirely on the website.

Snaps are untrusted JavaScript programs that execute safely inside the MetaMask application. To isolate Snaps from the rest of the application and provide a “fully virtualizable” execution environment, MetaMask uses Secure EcmaScript, or SES for short, a subset of JavaScript.

Among other things, SES allows programmers to restrict access to global JavaScript APIs and to isolate untrusted code from other parts of the application.

How to develop a Snap

To start with the Snaps development, you must have installed:

From Your Regular to Blockchain Engineer – Žarko’s Web3 Journey

CHECK IT OUT!

Then you need to install the MetaMask Flask, which is a separate extension for developers that provides access to additional unstable APIs. It is a developer-focused distribution of the MetaMask extension where they test and validate experimental features, like Snaps, before rolling them out to the main MetaMask applications. 

After that, install the Snaps CLI by typing the following command in your terminal.

yarn global add @metamask/snaps-cli

Optionally you can enter the next command to see detailed usage instructions.

mm-snap --help

To create a new Snap project, type:

mm-snap init

Then you need to create the Snap manifest file and name it `snap.manifest.json`. It must be located in the root directory of your npm package. Here’s an example manifest:

{
 "version": "0.7.0",
  "proposedName": "@metamask/template-snap",
  "description": "A MetaMask Snap template.",
  "repository": {
    "type": "git",
    "url": "https://github.com/MetaMask/template-snap.git"
  },
  "source": {
    "shasum": "w3FltkDjKQZiPwM+AThnmypt0OFF7hj4ycg/kxxv+nU=",
    "location": {
      "npm": {
        "filePath": "dist/bundle.js",
        "iconPath": "images/icon.svg",
        "packageName": "@metamask/template-snap",
        "registry": "https://registry.npmjs.org/"
      }
    }
  },
  "initialPermissions": {
    "snap_confirm": {}
  },
  "manifestVersion": "0.1"
}

As we said, Snaps execute in a sandboxed environment that’s running Secure EcmaScript. There is no DOM, Node.js builtins, and platform-specific APIs other than MetaMask’s `wallet` global object. So anything that relies on the DOM won’t work, and any Node builtins have to be bundled along with the Snap as well.

Because of that, Snaps must be published as a single .js file containing the entire source code and all dependencies. To automatically find all dependencies via your specified main entry point and output a bundle file to your specified output path, run the following command:

mm-snap build

Snaps have an “ephemeral” lifecycle, which means that if MetaMask detects that a Snap becomes unresponsive, it will be shut down. According to official documentation, a snap is considered “unresponsive” if:

  1. It has not received a JSON-RPC request for 30 seconds
  2. It takes more than 60 seconds to process a JSON-RPC request

Stopped Snaps are started whenever they receive a JSON-RPC request unless they have been disabled. If a snap is disabled, the user must re-enable it before starting again.

To run your Snap, type:

mm-snap serve

Polkadot Snap PoC

Polkadot Snap enables the Polkadot network inside MetaMask. First, one needs to inject Polkadot snap as a web3 provider using Metamask Polkadot Adapter by calling `injectMetamaskPolkadotSnapProvider` function. If only `network` argument is provided, a predefined configuration for a specific network will be used.

The second step is to install the Snap itself. Once Snap is installed, a new Polkadot account is generated. 

And finally, one needs to invoke Metamask Snap API.

Account details such as address, public key, and balance can be obtained through Metamask Snap API. For example, to get the public key for the generated account, call `getPublicKey()` function. Similarly, to get balance for the generated account, invoke `getBalance()` function.

Sending a transaction is a three-step process (generate a payload, generate a signature and send a transaction), and it can be done using the following code snippet:

const amount = "1000000000";
const recipient = "5DW5CXHWbM13Az7aetLQVUEviNq8WeXFQanHNPVMmzyRYKvX";

// get injected extension
const provider = await getInjectedMetamaskExtension();
if(provider) {
  // fetch metamask polkadot snap API
  const api = await provider.getMetamaskSnapApi();

  // send transaction
  const txPayload = await api.generateTransactionPayload(amount, recipient);
  const signedTx = await provider.signer.signPayload(txPayload.payload);
  const txHash = await api.send(signedTx.signature, txPayload);

  // subscribe to transaction events
  const polkadotEventApi = await api.getEventApi();
  // handleTransactionIncluded and handleTransactionFinalized are callbacks defined somewhare outside this code
  polkadotEventApi.subscribeToTxStatus(txHash, handleTransactionIncluded, handleTransactionFinalized);
}

Bitcoin Snap PoC

Bitcoin Snap enables MetaMask users to interact with the Bitcoin Blockchain. To run this Snap locally, one needs to run Bitcoin Node in the local environment as well or to provide Bitcoin Node API Endpoint. Since Snaps are essentially JavaScript programs, the recommendation is to use Bcoin

Bcoin is an alternative implementation of the Bitcoin protocol, written in JavaScript and C/C++ for Node.js. It is well tested and aware of all known consensus rules.

By running `yarn install` and then `yarn start`, the Snap will spin up in the development mode. UI will be available at port 3000, Snap at port 8081, while Bcoin node instance at port 5000.

To get account wallet details, call `getAccount` function and pass “testnet” or “bitcoin” as a function parameter. It will return the Bitcoin account address out of your connected account’s private key.

To get the account’s balance on Bitcoin testnet or Bitcoin main blockchain network, run `getBalance` and pass `account` address and `network` string (“bitcoin” or “testnet”) as function arguments.

To send some bitcoins through this Snap, call the `createTransaction` function and pass `_network`, `_receiver` address, `_amount` to spend, and a number of `_blockConfirmations` as function arguments.

Conclusion

MetaMask wallet can extend its basic functionality by the MetaMask Plugin System, called Snaps. In this technical tutorial, we covered what Snaps are, how to start with the development of Snaps, and discussed the current architecture of Polkadot & Bitcoin Snap Proof of Concepts.

Of course, any open-source contributions to the following projects are welcome.

LinkedIn Twitter Facebook

Comments (0)

Your thoughts
Name
*Your email address will not be published.

four × 1 =

Interested in working with us?

Let’s find the right solution for your blockchain ideas.