> For the complete documentation index, see [llms.txt](/llms.txt).

# Create a Snap to estimate gas fees

This tutorial walks you through creating a Snap that estimates gas fees. The Snap uses the `fetch` API to request information from the internet, and displays custom information in an alert dialog.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

- [MetaMask Flask installed](/snaps/get-started/install-flask/)
- A text editor (for example, [VS Code](https://code.visualstudio.com/))
- [Node](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) version 20.11 or later
- [Yarn](https://yarnpkg.com/)

## Steps[​](#steps "Direct link to Steps")

### 1\. Set up the project[​](#1-set-up-the-project "Direct link to 1. Set up the project")

Create a new Snap project using the [@metamask/create-snap](https://github.com/MetaMask/snaps/tree/main/packages/create-snap)starter kit by running:

```
yarn create @metamask/snap gas-estimation-snap

```

Next, `cd` into the `gas-estimation-snap` project directory and run:

```
yarn install

```

This initializes your development environment with the required dependencies.

<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>Did you get a warning?</summary><div><div class="collapsibleContent_i85q"><div><p>You may get a warning such as:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">@lavamoat/allow-scripts has detected dependencies without configuration. explicit configuration required.</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">run </span><span class="token string" style="color:rgb(255, 121, 198)">"allow-scripts auto"</span><span class="token plain"> to automatically populate the configuration.</span><br></div></code></pre></div></div><p>You can resolve this error by running:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token function" style="color:rgb(80, 250, 123)">yarn</span><span class="token plain"> run allow-scripts auto</span><br></div></code></pre></div></div></div></div></div></details>

### 2\. (Optional) Customize your Snap's UX[​](#2-optional-customize-your-snaps-ux "Direct link to 2. (Optional) Customize your Snap's UX")

This Snap is generated from a TypeScript template Snap. We recommend customizing your Snap to improve its UX, but this is optional for testing. If you don't wish to customize your Snap, skip to [Step 3](#3-enable-network-access).

#### 2.1. Provide an icon[​](#21-provide-an-icon "Direct link to 2.1. Provide an icon")

[Optimize your metadata](/snaps/learn/best-practices/design-guidelines/#optimize-your-metadata) and display an icon for your Snap in MetaMask.

Create a new folder `images` in the Snap package `packages/snap/`:

```
mkdir packages/snap/images

```

Download [this gas.svg icon file](https://raw.githubusercontent.com/Montoya/gas-fee-snap/main/packages/snap/images/gas.svg)into that `images` folder.

<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>Icon attribution</summary><div><div class="collapsibleContent_i85q"><div><p>This is a free icon, "Gas" by Mello from the <a href="https://thenounproject.com/browse/icons/term/gas/" target="_blank" rel="noopener noreferrer" class="">Noun Project</a>.</p></div></div></div></details>

Your file structure should look like this:

```
gas-estimation-snap/
├─ packages/
│  ├─ site/
|  |  |- src/
|  |  |  |- App.tsx
|  |  ├─ package.json
|  |  |- ...(react app content)
|  |
│  ├─ snap/
|  |  ├─ images/
|  |  |  |- gas.svg
|  |  ├─ src/
|  |  |  |- index.test.ts
|  |  |  |- index.tsx
|  |  ├─ snap.manifest.json
|  |  ├─ package.json
|  |  |- ... (Snap content)
├─ package.json
├─ ... (other stuff)

```

Open `packages/snap/snap.manifest.json` in a text editor. This file contains the main configuration details for your Snap. Edit the `npm` object, within the `location` object, and add `iconPath` with the value `"images/gas.svg"` to point to your new icon:

snap.manifest.json

```
"location": {
  "npm": {
    "filePath": "dist/bundle.js",
    "iconPath": "images/gas.svg",
    "packageName": "snap",
    "registry": "https://registry.npmjs.org/"
  }
}

```

Open `packages/snap/package.json` in a text editor. Edit the `files` array and reference the `images/` folder:

package.json

```
"files": [
  "dist/",
  "images/",
  "snap.manifest.json"
],

```

#### 2.2. Update your Snap's name[​](#22-update-your-snaps-name "Direct link to 2.2. Update your Snap's name")

[Optimize your metadata](/snaps/learn/best-practices/design-guidelines/#optimize-your-metadata) and update your Snap's name in MetaMask. MetaMask uses the `proposedName` of the Snap, currently "TypeScript Example" in the template.

Open `packages/snap/snap.manifest.json` in a text editor. Edit the `"proposedName"` property within the metadata to provide a functional name such as "Gas Estimator":

snap.manifest.json

```
{
  "version": "0.1.0",
  "description": "An example Snap written in TypeScript.",
  "proposedName": "Gas Estimator",
  ...
}

```

#### 2.3. Update your Snap's button[​](#23-update-your-snaps-button "Direct link to 2.3. Update your Snap's button")

Open `packages/site/src/components/Buttons.tsx` in a text editor. Edit the `Button` property to provide functional label text such as "Estimate Gas":

Buttons.tsx

```
export const SendHelloButton = (props: ComponentProps<typeof Button>) => {
  return <Button {...props}>Estimate Gas</Button>;
};

```

These three updates are the minimum required to ensure that each user interaction with your Snap is well-informed. However, your Snap will function without these tweaks.

### 3\. Enable network access[​](#3-enable-network-access "Direct link to 3. Enable network access")

To enable your Snap to [access the internet using the fetch API](/snaps/features/network-access/), request the [endowment:network-access](/snaps/reference/permissions/#endowmentnetwork-access)permission in `packages/snap/snap.manifest.json`:

snap.manifest.json

```
"initialPermissions": {
  "snap_dialog": {},
  "endowment:rpc": {
    "dapps": true,
    "snaps": false
  },
  "endowment:network-access": {}
},

```

### 4\. Fetch gas fee estimates[​](#4-fetch-gas-fee-estimates "Direct link to 4. Fetch gas fee estimates")

Open `packages/snap/src/index.tsx`. This is the main code file for your Snap. To get a gas fee estimate, use the public API endpoint provided by [Open Source Ethereum Explorer](https://beaconcha.in/). Add the following `getFees()` function to the beginning of the `/packages/snap/src/index.tsx` file:

index.tsx

```
import type { OnRpcRequestHandler } from '@metamask/snaps-sdk'
import { Box, Text } from '@metamask/snaps-sdk/jsx'

async function getFees() {
  const response = await fetch('https://beaconcha.in/api/v1/execution/gasnow')
  return response.text()
}

```

Next, add the `Copyable` component to the second import of the file:

index.tsx

```
import type { OnRpcRequestHandler } from '@metamask/snaps-sdk'
import { Box, Text, Copyable } from '@metamask/snaps-sdk/jsx'

```

Modify the Snap RPC message handler that displays the dialog. This handler uses a switch statement to handle various request methods, but in this instance there is only one method, `hello`. For the `hello` method, the handler returns a call to MetaMask with the parameters to display a dialog, and passes some static strings.

Update the `hello` method with the following code:

index.tsx

```
case "hello":
  const fees = await getFees();
  return snap.request({
    method: "snap_dialog",
    params: {
      type: "alert",
      content: (
        <Box>
          <Text>Hello, <Bold>{origin}</Bold>!</Text>
          <Text>Current gas fee estimates:</Text>
          <Copyable value={fees} />
        </Box>
      ),
    }
  });

```

### 5\. Build and test your Snap[​](#5-build-and-test-your-snap "Direct link to 5. Build and test your Snap")

Complete the following steps to build and test your Snap:

#### 5.1. Build your Snap[​](#51-build-your-snap "Direct link to 5.1. Build your Snap")

From the command line, run `yarn start`. The following displays:

```
You can now view site in the browser.

  http://localhost:8000/

```

Open [localhost:8000](http://localhost:8000/) in your browser (with MetaMask Flask installed). A page like the following displays:

![Test dapp with template Snap](/assets/images/template-snap-71dab3e1010b6cdcd69aefc5739bbcdd.png) 

This is a template test dapp for installing and testing your Snap.

#### 5.2. Test your Snap[​](#52-test-your-snap "Direct link to 5.2. Test your Snap")

Select **Connect** to connect Flask to the dapp. After connecting, you're prompted to install the Snap with the following permissions:

- **Allow websites to communicate directly with this Snap.**
- **Access the internet.**
- **Display dialog windows in MetaMask.**

Next, select **Confirm** > **OK**.

Select the **Send message** button (or **Estimate gas** button, if you followed Step 2). A dialog prompt displays with the response from the gas fee API:

![Gas estimation dialog](/assets/images/gas-estimation-0a5ae2f873be0b8fd6226aff0fb3f531.png)

Congratulations, you have integrated a public API into MetaMask and displayed real-time gas fee estimates.

### Next steps[​](#next-steps "Direct link to Next steps")

You can improve your Snap's UX by:

- Completing [Step 2](#2-optional-customize-your-snaps-ux).
- Parsing the JSON response from the remote API.
- Formatting the fees for better readability.

Before publishing a Snap, it's also important to customize the metadata and properties of your Snap:

- Update the `location` in `snap.manifest.json` to your Snap's published location.
- Update the `description` in `snap.manifest.json` to a description of your Snap.
- Update the `name`, `version`, `description`, and `repository` fields of `/packages/snap/package.json` (even if you do not plan to publish your Snap to npm).
- Update the content of `/packages/site/src/pages/index.tsx` by changing the name of the method for showing gas fee estimates. If you change the method name in `/packages/site/src/pages/index.tsx`, ensure you change the method name in `/packages/snap/src/index.ts` to match.

note

When editing `source`, the `shasum` is set automatically when you build from the command line.

important

The `version` and `repository` fields in `snap.manifest.json` inherit the values from `package.json` and overwrite them in `snap.manifest.json`. We recommend updating `version` and `repository` in `package.json` first, then building your Snap project.

After you have made all necessary changes, you can [publish your Snap to npm](/snaps/how-to/publish-a-snap/).
