Icon HelpCircleForumIcon Link

āŒ˜K

Icon HelpCircleForumIcon Link
Intro /
Quickstart Frontend

Icon LinkBuilding a Frontend to Interact With Your Contract

To build a frontend application for the counter contract, we'll do the following:

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

Icon LinkInstall the Fuel Browser Wallet

Icon InfoCircle

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

Our frontend application will allow users to connect with a wallet, so you'll need to have a browser wallet installed.

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 setup your wallet, click the "Faucet" button in the wallet to get some testnet tokens.

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 with TypeScript using Create React App Icon Link.

npx create-react-app frontend --template typescript

The output should be similar to this:

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

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

project folder structure

Icon LinkInstall the fuels SDK dependency

The fuels package includes all the main tools you need to interact with your Sway programs and the Fuel network. The @fuel-wallet packages include everything you need to interact with user wallets.

Icon LinkInstalling

Move into the frontend folder by running:

cd frontend
Icon InfoCircle

fuels requires Node version 18.18.2 || ^20.0.0.

Install the following packages in your frontend folder:

npm install fuels@0.79.0 @fuels/react@0.18.0 @fuels/connectors@0.1.1 @tanstack/react-query@5.28.9

Icon LinkGenerate contract types

The fuels init command generates a fuels.config.ts file that is used by the SDK to generate contract types. Use the contracts flag to define where your contract folder is located, and the output flag to define where you want the generated files to be created.

Run the command below in your frontend folder to generate the config file:

npx fuels init --contracts ../counter-contract/ --output ./src/sway-api

Now that you have a fuels.config.ts file, you can use the fuels build command to rebuild your contract and generate types. Running this command will interpret the output ABI JSON from your contract and generate the correct TypeScript definitions. If you see the folder fuel-project/counter-contract/out you will be able to see the ABI JSON there.

Inside the fuel-project/frontend directory run:

npx fuels build

A successful process should print and output like the following:

Building..
Building Sway programs using built-in 'forc' binary
Generating types..
šŸŽ‰  Build completed successfully!
Icon InfoCircle

If you're having any issues with this part, try adding useBuiltinForc: false, to your fuels.config.ts config file to make sure it's using the same version of forc as your default toolchain.

Now you should be able to find a new folder fuel-project/frontend/src/sway-api.

Icon LinkModify the App

Inside the frontend/src folder let's add code that interacts with our contract.

Because we'll be using @fuels/react, first we need to wrap our app with the FuelProvider component.

Add the imports below to the top of your frontend/src/index.tsx file and setup a query client:

import { FuelProvider } from '@fuels/react';
import {
  FuelWalletConnector,
  FuelWalletDevelopmentConnector,
  FueletWalletConnector,
} from '@fuels/connectors';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
 
const queryClient = new QueryClient();

Next, modify your frontend/src/index.tsx file to wrap the App component with the FuelProvider and QueryClientProvider components.

   <QueryClientProvider client={queryClient}>
      <FuelProvider
        fuelConfig={{
          connectors: [
            new FuelWalletConnector(),
            new FuelWalletDevelopmentConnector(),
            new FueletWalletConnector(),
          ],
        }}
      >
        <App />
      </FuelProvider>
    </QueryClientProvider>

Next, change the file fuel-project/frontend/src/App.tsx to:

import { useEffect, useState } from "react";
import {
  useConnectUI,
  useIsConnected,
  useWallet
} from '@fuels/react';
// Import the contract factory -- you can find the name in src/contracts/contracts/index.ts.
// You can also do command + space and the compiler will suggest the correct name.
import { CounterContractAbi__factory  } from "./sway-api"
import type { CounterContractAbi } from "./sway-api";
 
const CONTRACT_ID = 
  "0x...";
 
export default function Home() {
  const [contract, setContract] = useState<CounterContractAbi>();
  const [counter, setCounter] = useState<number>();
  const { connect, isConnecting } = useConnectUI();
  const { isConnected } = useIsConnected();
  const { wallet } = useWallet();
 
  useEffect(() => {
    async function getInitialCount(){
      if(isConnected && wallet){
        const counterContract = CounterContractAbi__factory.connect(CONTRACT_ID, wallet);
        await getCount(counterContract);
        setContract(counterContract);
      }
    }
    
    getInitialCount();
  }, [isConnected, wallet]);
 
  const getCount = async (counterContract: CounterContractAbi) => {
    try{
      const { value } = await counterContract.functions
      .count()
      .txParams({
        gasPrice: 1,
        gasLimit: 100_000,
      })
      .get();
      setCounter(value.toNumber());
    } catch(error) {
      console.error(error);
    }
  }
 
  const onIncrementPressed = async () => {
    if (!contract) {
      return alert("Contract not loaded");
    }
    try {
      await contract.functions
      .increment()
      .txParams({
        gasPrice: 1,
        gasLimit: 100_000,
      })
      .call();
      await getCount(contract);
    } catch(error) {
      console.error(error);
    }
  };
 
  return (
    <div style={styles.root}>
      <div style={styles.container}>
        {isConnected ? (
          <>
            <h3 style={styles.label}>Counter</h3>
            <div style={styles.counter}>
              {counter ?? 0}
            </div>
            <button
            onClick={onIncrementPressed}
            style={styles.button}
            >
              Increment Counter
            </button>
          </>
        ) : (
          <button
          onClick={() => {
            connect();
          }}
          style={styles.button}
          >
            {isConnecting ? 'Connecting' : 'Connect'}
          </button>
        )}
      </div>
    </div>
  );
}
 
const styles = {
  root: {
    display: 'grid',
    placeItems: 'center',
    height: '100vh',
    width: '100vw',
    backgroundColor: "black",
  } as React.CSSProperties,
  container: {
    color: "#ffffffec",
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
  } as React.CSSProperties,
  label: {
    fontSize: "28px",
  },
  counter: {
    color: "#a0a0a0",
    fontSize: "48px",
  },
  button: {
    borderRadius: "8px",
    marginTop: "24px",
    backgroundColor: "#707070",
    fontSize: "16px",
    color: "#ffffffec",
    border: "none",
    outline: "none",
    height: "60px",
    padding: "0 1rem",
    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.

Click the "Connect" button and select "Fuel Wallet Development" to connect your wallet. Once connected, you should see the counter value and increment button:

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

To develop and test faster, we recommend using the fuels dev command to start a local node and automatically redeploy and generate types for your contract on each change.

Once you're ready to redeploy your contract to the testnet, here are the steps you should take to get your frontend and contract back in sync:

  • In your frontend directory, re-run this command: npx fuels 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, 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.