Icon LinkBuilding a Frontend to Interact With Your Contract

To build out our frontend application, we'll do the following:

  1. Install the Fuel Browser Wallet.
  2. Initialize a React project.
  3. Install the fuels SDK dependency.
  4. Write our frontend code.
  5. Run our project.

Icon LinkInstall the Fuel Browser Wallet

Note: Make sure your browser is using the latest version of chromium.

Our front end application will need to interact with the Fuel Network, so we'll need to have a browser wallet installed for us to do so.

Before going to the next steps, install the Fuel Wallet here Icon Link.

If you have previously installed the wallet, make sure you have updated to the latest version.

Once you've installed the wallet, take the address of your wallet and use it to get some coins from the testnet faucet Icon Link.

Icon LinkInitialize a React project

To split our project's contract from frontend code, let's initialize our frontend project: assuming that your terminal is open at your contract's folder /home/user/path/to/counter-contract let's go back up one directory.

cd ..

Now, initialize a react project using Create React App Icon Link.

npx create-react-app frontend --template typescript

The output should be similar to:

Success! Created frontend at Fuel/fuel-project/frontend

You should now have your outer folder, fuel-project, with two folders inside: counter-contract and frontend

project folder structure

Icon LinkInstall the fuels SDK dependency

The fuels umbrella package includes all the main tools you need for your frontend; Wallet, Contracts, Providers, and more.

Also, it contains the routines for ABI TypeScript generation.

ABI stands for Application Binary Interface. ABI's inform the application the interface to interact with the VM, in other words, they provide info to the APP such as what methods a contract has, what params, types it expects, etc...

Icon LinkInstalling

Move into the frontend folder, then run:

cd frontend

Install fuels and @fuel-wallet/sdk.

npm install fuels@0.60.0 @fuel-wallet/sdk@0.13.0 --save

If the installation went correctly the result will be similar to this:

added 114 packages, and audited 115 packages in 9s

Next, update the TypeScript configuration at tsconfig.json to add the Fuel Wallet types:

{
  "compilerOptions": {
    "types": ["@fuel-wallet/sdk"]
  }
}

Icon LinkGenerating contract types

To make it easier to interact with our contract we use fuels typegen command to interpret the output ABI JSON from our contract, and generate Typescript definitions based on it. This JSON was created when we executed the forc build command to compile our Sway Contract into binary.

If you see the folder fuel-project/counter-contract/out you will be able to see the ABI JSON there. If you want to learn more, read the ABI spec .

Inside the fuel-project/frontend directory run:

npx fuels typegen -i ../counter-contract/out/debug/*-abi.json -o ./src/contracts

A successful process should print and output like the following:

Generating files..

 - src/contracts/CounterContractAbi.d.ts
 - src/contracts/factories/CounterContractAbi__factory.ts
 - src/contracts/index.ts

Done.⚡

Now you should be able to find a new folder fuel-project/frontend/src/contracts. This folder was auto-generated by our fuels typegen command, and these files abstract the work we would need to do to create a contract instance, and generate a complete TypeScript interface to the Contract, making easy to develop.

Icon LinkModify the App

Inside the frontend/src folder let's add code that interacts with our contract. Change the file fuel-project/frontend/src/App.tsx to:

File: ./frontend/src/App.tsx

import { useEffect, useState } from "react";
import "./App.css";
// Import the contract factory -- you can find the name in index.ts.
// You can also do command + space and the compiler will suggest the correct name.
import { CounterContractAbi__factory } from "./contracts";
 
// The address of the contract deployed the Fuel testnet
const CONTRACT_ID =
  "0x...";
 
function App() {
  const [connected, setConnected] = useState<boolean>(false);
  const [account, setAccount] = useState<string>("");
  const [counter, setCounter] = useState<number>(0);
  const [loaded, setLoaded] = useState(false);
 
  useEffect(() => {
    setTimeout(() => {
      checkConnection();
      setLoaded(true);
    }, 200)
    if (connected) getCount();
  }, [connected])
 
  async function connect() {
    if (window.fuel) {
      try {
        await window.fuel.connect();
        const [account] = await window.fuel.accounts();
        setAccount(account);
        setConnected(true);
      } catch (err) {
        console.log("error connecting: ", err);
      }
    }
  }
 
  async function checkConnection() {
    if (window.fuel) {
      const isConnected = await window.fuel.isConnected();
      if (isConnected) {
        const [account] = await window.fuel.accounts();
        setAccount(account);
        setConnected(true);
      }
    }
  }
 
  async function getCount() {
    if (window.fuel) {
      const wallet = await window.fuel.getWallet(account);
      const contract = CounterContractAbi__factory.connect(CONTRACT_ID, wallet);
      const { value } = await contract.functions.count().simulate();
      setCounter(value.toNumber());
    }
  }
 
  async function increment() {
    if (window.fuel) {
      const wallet = await window.fuel.getWallet(account);
      const contract = CounterContractAbi__factory.connect(CONTRACT_ID, wallet);
      // Creates a transactions to call the increment function
      // because it creates a TX and updates the contract state this requires the wallet to have enough coins to cover the costs and also to sign the Transaction
      try {
        await contract.functions.increment().txParams({ gasPrice: 1 }).call();
        getCount();
      } catch (err) {
        console.log("error sending transaction...", err);
      }
    }
  }
 
  if (!loaded) return null
 
  return (
    <>
      <div className="App">
        {
          connected ? (
            <>
              <h3>Counter: {counter}</h3>
              <button style={buttonStyle} onClick={increment}>
                Increment
              </button>
            </>
          ) : (
            <button style={buttonStyle} onClick={connect}>Connect</button>
          )
        }
      </div>
    </>
  );
}
 
export default App;
 
const buttonStyle = {
  borderRadius: "48px",
  marginTop: "10px",
  backgroundColor: "#03ffc8",
  fontSize: "20px",
  fontWeight: "600",
  color: "rgba(0, 0, 0, .88)",
  border: "none",
  outline: "none",
  height: "60px",
  width: "400px",
  cursor: "pointer"
}

Finally, replace the value of the CONTRACT_ID variable at the top of your App.tsx file with the address of the contract you just deployed.

Icon LinkRun your project

Inside the fuel-project/frontend directory run:

npm start
Compiled successfully!

You can now view frontend in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.4.48:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

screenshot of the UI

Icon LinkYou just built a fullstack dapp on Fuel! ⛽

Here is the repo for this project Icon Link. If you run into any problems, a good first step is to compare your code to this repo and resolve any differences.

Tweet us @fuel_network Icon Link letting us know you just built a dapp on Fuel, you might get invited to a private group of builders, be invited to the next Fuel dinner, get alpha on the project, or something 👀.

Icon LinkUpdating The Contract

If you make changes to your contract, here are the steps you should take to get your frontend and contract back in sync:

  • In your contract directory, run forc build
  • In your contract directory, redeploy the contract by running this command and following the same steps as above to sign the transaction with your wallet: forc deploy --testnet
  • In your frontend directory, re-run this command: npx fuels typegen -i ../counter-contract/out/debug/*-abi.json -o ./src/contracts
  • In your fuel-project/frontend directory, update the contract ID in your App.tsx file

Icon LinkNeed Help?

Get help from the team by posting your question in the Fuel Forum Icon Link.

Was this page helpful?