DEV Community

Nacho Colomina Torregrosa
Nacho Colomina Torregrosa

Posted on • Edited on

1 1 2

Creating a React Hook to integrate the Stellar Wallets Kit

Introduction

I'm working in a Symfony / React application which uses the stellar-wallets kit. To use the kit I've created a React hook to integrate such component and manage it easily. As I like sharing my knowledge with the community, this short article shows how I've developed the wallet hook.

The Stellar-Wallets kit

The stellar-wallets kit component allows developers to handle all Stellar Wallets at once with a simple API and without caring about individual configurations for each one of them.
It supports many wallets such as Freighter, Albedo and xBull

Creating the React hook

Before starting to create the hook, we have to install the stellar-wallets dependency:

npm install @creit.tech/stellar-wallets-kit
Enter fullscreen mode Exit fullscreen mode

Now it's time for creating the hook. Let's see the code:

import { FREIGHTER_ID, FreighterModule, ISupportedWallet, StellarWalletsKit, WalletNetwork, xBullModule } from "@creit.tech/stellar-wallets-kit";
import { useEffect, useState } from "react";

export interface Wallet {
    wallet: StellarWalletsKit,
    walletConnected: boolean,
    connectWallet: () => void,
    disconnectWallet: () => void
}

export const useStellarWallet = (network: WalletNetwork): Wallet => {
    const [wallet, setWallet] = useState<StellarWalletsKit>(null);
    const [walletConnected, setWalletConnected] = useState<boolean>(false);

    useEffect(
        () => {
            const kit: StellarWalletsKit = new StellarWalletsKit({
                network: network,
                selectedWalletId: FREIGHTER_ID,
                modules: [
                  new xBullModule(),
                  new FreighterModule(),
                ]
            });
            setWallet(kit);
        }, []
    )


    const connectWallet = async() => {
        await wallet.openModal({
            onWalletSelected: async (option: ISupportedWallet) => {
              wallet.setWallet(option.id);
              setWalletConnected(true);
            }
        });
    }

    const disconnectWallet = () => {
        setWallet(null);
        setWalletConnected(false);
    }

    return {
        wallet,
        walletConnected,
        connectWallet,
        disconnectWallet
    } as Wallet
}
Enter fullscreen mode Exit fullscreen mode

Let's explain the code step-by-step:

  • The Wallet interface will be used as a type returned by the hook.
  • The wallet/setWallet state allows us to manage the wallet variable state. This variable is an instance of StellarWalletsKit object.
  • The walletConnected/setWalletConnected state allows us to manage whether the wallet is connected or not.
  • The "useEffect" hook creates the instance of the StellarWalletsKit and sets it to the wallet state variable.
  • The connectWallet function opens the StellarWalletsKit modal so that you can choose the wallet you want to work with (in this case, X_BULL or Freigther). After chosen, it sets the "walletConnected" state variable to true.
  • The "disconnectWallet" removes the wallet (sets the "wallet" state variable to null) and sets the "walletConnected" state variable to false.
  • Finally, the hook returns an instance of the Wallet interface.

Using the hook

I'm using React MUI as a component library and I wanted to create a button in the header bar so that it can be used to connect the wallet throughout the entire application.
To do it, I decided to use React contexts. Contexts are an efficient way to share logic and data between components.

Creating the wallet context

Creating the context is very simple. We only have to use the react "createContext" function.

import { createContext } from "react";
import { Wallet } from "../hooks/Wallet/StellarWalletsHook";

export const WalletContext = createContext<Wallet>(null);
Enter fullscreen mode Exit fullscreen mode

We specify that the context data type is an instance of the Wallet interface we created in the previous section.

Providing the context

So far, we have created the context. Now it's time to provide it so that the rest of the components can use it. Let's do it:

export default function App(props: any) {

    const wallet: Wallet = useStellarWallet(WalletNetwork.TESTNET);

    return (
      <Fragment>
        <CssBaseline />
        <WalletContext.Provider value={wallet}>
          <Router>
            <Routes>
              <Route path="/login" element={<SignIn />} />
                <Route path="/app" element={<ProtectedRoute children={<Layout pathSlug={props.pathSlug}/> } /> } >
                    <Route path="home" index element={<Home />} />
                    <Route path="home-investor" element={<HomeInvestor />} />
                    <Route path="blogs" element={<Blogs />} />
                    <Route path="create-project" element={<CreateInvestmentProject />} />
                    <Route path="project/:id/start" element={<StartInvestmentProject />} />
                    <Route path="project/:id/invest" element={<SendInvestmentDeposit />} />
                </Route>
            </Routes>
          </Router>
        </WalletContext.Provider>
      </Fragment>
    );
}
Enter fullscreen mode Exit fullscreen mode

The WalletContext englobes the rest of the component tree so that the child components can access to the wallet state.

Using the context

Finally, it's time of using the context. To achieve it, we can us the react useContext hook which will give us access to the wallet hook capabilities.

const wallet: Wallet = React.useContext(WalletContext);
const [walletStatusColor, setWalletStatusColor] = React.useState<any>('secondary');
const [walletConnectedAlertOpened, setWalletConnectedAlertOpened] = React.useState<boolean>(false);
Enter fullscreen mode Exit fullscreen mode

Let's explain each line:

  • The first line gives us access to the wallet so that we can use its methods and states.
  • The second line creates an state variable to manage the badge color we will set to the wallet icon badge when it is connected or disconnected.
  • The third line creates an state variable which will be used to open a MUI SnackBar to inform that the wallet is already connected.

Let's write the code to allow users to connect their wallets.

React.useEffect(
    () => {
        (wallet.walletConnected) 
            ? setWalletStatusColor('success')
            : setWalletStatusColor('secondary')
        ;

    }, [wallet.walletConnected]
 )

const handleConnectWallet = async() => {
   if(wallet.walletConnected) {
      handleOpenWalletConnected();
      return;
   }

   wallet.connectWallet();
}

const handleOpenWalletConnected = () => {
   setWalletConnectedAlertOpened(true);
};

const handleCloseWalletConnected = (event?: React.SyntheticEvent | Event,reason?: SnackbarCloseReason) => {
    if (reason === 'clickaway') {
      return;
    }

    setWalletConnectedAlertOpened(false);
};

// ..........

<Snackbar open={walletConnectedAlertOpened} autoHideDuration={6000} onClose={handleCloseWalletConnected}>
    <Alert
      onClose={handleCloseWalletConnected}
      severity="success"
      variant="filled"
      sx={{ width: '100%' }}
    >
      Wallet already connected
    </Alert>
 </Snackbar>

<IconButton size="large" aria-label="show 4 new mails" color="inherit" onClick={handleConnectWallet}>
    <Badge color={walletStatusColor} variant="dot">
         <WalletIcon />
    </Badge>
</IconButton>
Enter fullscreen mode Exit fullscreen mode

Let's review the above code step-by-step:

  • The wallet.walletConnected effect change when such state variable changes. If the wallet is connected the color turns to "success" and if it is not connected the color remains "secondary".

  • The handleConnectWallet method uses the context provided wallet to check whether it is connected or not. If so, it executes the handleOpenWalletConnected method to show an MUI SnackBar to inform that the wallet is already connected. Otherwise is uses de hook connectWallet method to show the stellar-wallets-kit modal.

  • The handleCloseWalletConnected is used to close the SnackBar only when the user clicks on the close button.

  • The SnackBar only appears when the walletConnectedAlertOpened state variable is true and uses the handleCloseWalletConnected as a close handler method.

  • Finally, the MUI IconButon triggers the handleConnectWallet method on the click event. The MUI Badge uses the walletStatusColor state variable to set the color.

Conclusion

By using the React context capabilities, I have managed to gain access to the wallet data and functions through the entire application in an efficient way.
I've been using react for a short time and there may be faster and more efficient ways to achieve the objective of this post. If you know better ways, let me now in the comments so i can learn them too. :)

If you like my content and enjoy reading it and you are interested in learning more about PHP, you can read my ebook about how to create an operation-oriented API using PHP and the Symfony Framework. You can find it here: Building an Operation-Oriented Api using PHP and the Symfony Framework: A step-by-step guide

Please leave your appreciation by commenting on this post!

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Imagine monitoring actually built for developers

Billboard image

Join Vercel, CrowdStrike, and thousands of other teams that trust Checkly to streamline monitor creation and configuration with Monitoring as Code.

Start Monitoring

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay