Behind the Scenes: Creating the AirSwap Member Dashboard App
Table of ContentsIntroductionWhat is the AirSwap Voter Rewards App?App Features I DevelopedMentorshipCode ReviewsTypeScriptWagmi LibraryCustom React ComponentsVariable NamingRegressionsLaunch DayPutting Apps into ProductionConclusionIntroductionIn this post, I'll share my experience and the key lessons I learned while building the AirSwap Member Dashboard app. This app provides users with the ability to stake AST tokens, vote on proposals that influence the AirSwap protocol, and claim re...

How to Build an Accordion Component
I've been actively involved in the frontend development of the new AirSwap Member Dashboard app. AirSwap currently leverages a platform named Activate for user stake management. However, within a month, Activate will be phased out, prompting the development of a new app for $AST token stakers. A notable feature of this app is the Accordion component, which I'll discuss here, illustrating its creation with React, Radix, and TailwindCSS.What is Radix-UI?Radix-UI logoRadix-UI is an ope...
My Experience as a Raid Guild Apprentice
My Experience as a Raid Guild Apprentice“If you want to go fast, go alone. If you want to go far, go together...”My journey as a software developer started about 15 months ago. Coming from a non-technical background in marketing, I didn't know many engineers. Knowing the right people won't make you smarter, but they can point you in the right direction and you'll learn more efficiently. Having a strong network of people is half the battle to success. In January, 2022 I started ...
Web Developer @ AirSwap // Building DeFi // React, TypeScript, Tailwind, Frontend Developer.

Introduction
What is Wagmi
Component Structure
Main
WalletConnection
WalletConnectionModal
UserAccountDetail
Main Config Hooks
WalletConnection Component
WalletConnectionModal Component
Rabby Wallet
Conclusion

For a Web3 application, a wallet connection is essential. It's the equivalent of a user signing in with a username and password, except using a wallet as a form of identification. By connecting your wallet to an app, you have the ability to sign transactions and interact with the app in a meaningful way.
This blog post will cover how to implement a Web3 wallet connection. It’s how it was implemented on the AirSwap Member Dashboard app.
With this setup, a user clicks the “CONNECT” button, which opens a Modal containing various wallets for a user to chose from. This setup relies on TypeScript, React, and the Wagmi library for Ethereum connections.
Wagmi is a collection of React Hooks containing everything you need to start working with Ethereum. It makes it easy to "Connect Wallet," display ENS and balance information, sign messages, interact with contracts, and much more — all with caching, request deduplication, and persistence. You can see more on the official docs: https://wagmi.sh

There are 4 major components involved:
Main - Code. This is the main React component of the project, but it contains 2 hooks with important configuration data.
WalletConnection - Code. This component is responsible for rendering the “CONNECT” button, and contains logic for whether or not to render the Wallet Connection Modal.
WalletConnection Modal - Code. This component is responsible rendering a selection of wallets that a user can use to connect to the application.
UserAccountDetail - Code. This component it’s mostly for aesthetic purposes. It’s used to render a user’s ENS avatar, and a disconnect button.
In our main React file, Main.tsx, there are 2 main hooks that we use to set up our configuration, and 1 wrapper that we place around our entire app.
configureChains
The first hook is called configureChains. This allows you to set up specific chains you want your app to use, as well as setting up your RPC providers. There’s also optional functionality in this hook that lets you setup batched multi-calls, but that’s beyond the scope of this blog post.
const { chains, publicClient, webSocketPublicClient } = configureChains(
[mainnet, goerli, avalanche, bsc, polygon],
[
infuraProvider({ apiKey: import.meta.env.VITE_INFURA_API_KEY || "" }),
publicProvider(),
],
);
In the code snippet above, configureChains takes in arguments of an array of chains, and an array of RPC providers. The array of chains includes values like mainnet, goerli, and avalanche. This means that our app will support those chains. The value infuraProvider configures our app to use Infura as an RPC provider.
configureChains returns several values which get passed into the createConfighook.
createConfig
createConfig is a hook where you can setup more options, such as the connectors you want to use. “Connectors” in this context is a technical term for wallets. You can pass in popular options such as MetaMask and Coinbase Wallet. createConfig also allows you to select options such as auto-connect, or to pass in a web socket connection.
const config = createConfig({
autoConnect: true,
publicClient,
webSocketPublicClient,
queryClient,
connectors: [
new MetaMaskConnector({ chains }),
new InjectedConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: "AirSwap Member Dashboard",
appLogoUrl: AirSwapLogo,
},
}),
new WalletConnectConnector({
chains,
options: {
projectId: import.meta.env.VITE_WALLETCONNECT_ID,
},
}),
],
});

The variable name of this component is WalletConnection. It renders 3 things:
A “connect” button when the user isn’t connected. If the user is connected, the button shows the wallet address or ENS name.
WalletConnectionModal, which contains is where the user can select a wallet to connect.
{showConnectionModal && (
<WalletConnectionModal
setShowConnectionModal={setShowConnectionModal}
/>
)}
showConnectionModal gets set to true when a user clicks the “connect” button, but isn’t yet connected to the app.
It renders UserAccountDetail if the user’s wallet is connected. Wagmi has a hook called useAccount, which returns a boolean value isConnected. We can use the variable isConnected to show or hide things in our JSX code.
{isConnected && (
<UserAccountDetail
setShowUserAccountDetail={setShowUserAccountDetail}
showUserAccountDetail={showUserAccountDetail}
/>
)}
**handleShowConnectionModal**
This function gets called when a user isn’t yet connected, clicks the “connect” button, but hasn’t yet connected to a chosen wallet. This function changes the values of showConnectionModal and showUserAccountDetail. These 2 variables control the visibility of WalletConnectionModal and UserAccountDetail, respectively.
const handleShowConnectionModal = () => {
!isConnected
? setShowConnectionModal(true)
: setShowUserAccountDetail(!showUserAccountDetail);
};

This component will be displayed after a user clicks the “connect” button. It displays various wallets that a user can use to connect to the application.
Within the JSX code of WalletConnectionModal, there’s an unnamed function that loops over an array of connectors. connectors is an array containing all the wallets that users can connect to, such as MetaMask or Coinbase Wallet.
{connectors
.filter(
(connector) =>
connector.ready &&
// Don't show inject if it's MetaMask (we're already showing it)
!(connector.id === "injected" && connector.name === "MetaMask"),
)
.map((connector: Connector) => {
const isInjected = connector.id === "injected";
return (
<button
className="flex flex-row items-center rounded border border-gray-800 bg-gray-900 p-4 hover:bg-gray-800 disabled:cursor-not-allowed font-medium",
)}
disabled={!connector.ready}
onClick={() => connect({ connector })}
key={connector.id}
>
The primary aspect of the function involves a map function that iterates over the connectors array and renders each one onto its own button.. Within this function there’s extra logic that checks if it’s an “injected” connector. More on injected connectors in the next section.

Rabby is a competing wallet to MetaMask. It has more advanced features such as security warnings, and the ability to import multiple private keys into 1 installation. However, enabling Rabby presented some challenges that I’ll cover below.
What is an Injected Connector?
An injected connector refers to a user's default wallet. It's the wallet that a DApp will use if no other wallet is connected. If you're using Rabby, there's a switch you can toggle that sets it to your injected connector.


If you look again at the code in WalletConnectionModal, you’ll see 3 different things related to the injected connector:
A boolean value called injectedIsMetamask, which is a React state variable. This value gets set in a useEffect after checking whether or not Rabby wallet is active. If injectedIsMetaMask is true, Rabby will be shown instead of MetaMask on the connection modal.
A useEffect hook checking if the connecting wallet is using Rabby. Here’s the code used for that check:
useEffect(() => {
const rabbyConnector = connectors.find(
(connector) => connector.name.toLowerCase() === "rabby wallet",
);
if (rabbyConnector && !rabbyConnector.options.getProvider()._isRabby) {
// Rabby is forwarding to metamask
setInjectedIsMetaMask(true);
}
}, [connectors]);
Note that on the rabbyConnector object, if the getProvider method does not contain _isRabby, then we set the value is injectedIsMetaMask to be true.
In the JSX before the map function, we filter through the connectors array before looping over it with the map method. Here, we’re filtering to see if MetaMask is the injected wallet connector. It gets filtered out, because in our main.tsx component, we’re adding in MetaMask to our connectors array in the createConfig hook. (Scroll up the section “Main config hooks” to see that code snippet).
There’s another useEffect hook in this component:
useEffect(() => {
isConnected && setShowConnectionModal(false);
// close modal when WalletConnect or Coinbase modal is open
pendingConnector && setShowConnectionModal(false);
}, [isConnected, pendingConnector, setShowConnectionModal]);
This code was added after a small bug was discovered with WalletConnect, Coinbase Wallet, and any other wallet that uses its own modal.
When connecting to WalletConnect, we found that the WalletConnectionModal was overlaying:

The code snippet above fixed this bug, so WalletConnect (and Coinbase Wallet) rendered correctly like so:

This component is mostly for aesthetic purposes. There are 2 functional aspects worth mentioning:
Disconnect function: This utilizes the Wagmi hook useDisconnect. Here’s the code: const { disconnect } = useDisconnect();. Calling the disconnect function on the button will log out the user.
ENS Avatar: this is a nice touch if a user has an ENS name associated with an address. It builds familiarity and trust with the app. Here’s the code:
const { data: ensName } = useEnsName({ address, chainId: 1 });
const { data: avatarUrl } = useEnsAvatar({
name: ensName,
chainId: 1,
});
With this code in place, we can use avatarUrl (which is returned from the useEnsAvatar hook, to render a user’s avatar:

https://vimeo.com/877284150?share=copy
In this post we covered a technical explanation of how to implement a Web3 wallet connection using Wagmi hooks and React.
We explored key components such as the Main Config Hooks, Wallet Connection Component, and Wallet Connection Modal, each playing a vital role in creating a seamless and secure user experience within decentralized applications.
This demonstrates the simplicity of the implementation. Let me know if my explanation wasn’t simple enough, or what I can do to improve. Thanks for reading!

Introduction
What is Wagmi
Component Structure
Main
WalletConnection
WalletConnectionModal
UserAccountDetail
Main Config Hooks
WalletConnection Component
WalletConnectionModal Component
Rabby Wallet
Conclusion

For a Web3 application, a wallet connection is essential. It's the equivalent of a user signing in with a username and password, except using a wallet as a form of identification. By connecting your wallet to an app, you have the ability to sign transactions and interact with the app in a meaningful way.
This blog post will cover how to implement a Web3 wallet connection. It’s how it was implemented on the AirSwap Member Dashboard app.
With this setup, a user clicks the “CONNECT” button, which opens a Modal containing various wallets for a user to chose from. This setup relies on TypeScript, React, and the Wagmi library for Ethereum connections.
Wagmi is a collection of React Hooks containing everything you need to start working with Ethereum. It makes it easy to "Connect Wallet," display ENS and balance information, sign messages, interact with contracts, and much more — all with caching, request deduplication, and persistence. You can see more on the official docs: https://wagmi.sh

There are 4 major components involved:
Main - Code. This is the main React component of the project, but it contains 2 hooks with important configuration data.
WalletConnection - Code. This component is responsible for rendering the “CONNECT” button, and contains logic for whether or not to render the Wallet Connection Modal.
WalletConnection Modal - Code. This component is responsible rendering a selection of wallets that a user can use to connect to the application.
UserAccountDetail - Code. This component it’s mostly for aesthetic purposes. It’s used to render a user’s ENS avatar, and a disconnect button.
In our main React file, Main.tsx, there are 2 main hooks that we use to set up our configuration, and 1 wrapper that we place around our entire app.
configureChains
The first hook is called configureChains. This allows you to set up specific chains you want your app to use, as well as setting up your RPC providers. There’s also optional functionality in this hook that lets you setup batched multi-calls, but that’s beyond the scope of this blog post.
const { chains, publicClient, webSocketPublicClient } = configureChains(
[mainnet, goerli, avalanche, bsc, polygon],
[
infuraProvider({ apiKey: import.meta.env.VITE_INFURA_API_KEY || "" }),
publicProvider(),
],
);
In the code snippet above, configureChains takes in arguments of an array of chains, and an array of RPC providers. The array of chains includes values like mainnet, goerli, and avalanche. This means that our app will support those chains. The value infuraProvider configures our app to use Infura as an RPC provider.
configureChains returns several values which get passed into the createConfighook.
createConfig
createConfig is a hook where you can setup more options, such as the connectors you want to use. “Connectors” in this context is a technical term for wallets. You can pass in popular options such as MetaMask and Coinbase Wallet. createConfig also allows you to select options such as auto-connect, or to pass in a web socket connection.
const config = createConfig({
autoConnect: true,
publicClient,
webSocketPublicClient,
queryClient,
connectors: [
new MetaMaskConnector({ chains }),
new InjectedConnector({ chains }),
new CoinbaseWalletConnector({
chains,
options: {
appName: "AirSwap Member Dashboard",
appLogoUrl: AirSwapLogo,
},
}),
new WalletConnectConnector({
chains,
options: {
projectId: import.meta.env.VITE_WALLETCONNECT_ID,
},
}),
],
});

The variable name of this component is WalletConnection. It renders 3 things:
A “connect” button when the user isn’t connected. If the user is connected, the button shows the wallet address or ENS name.
WalletConnectionModal, which contains is where the user can select a wallet to connect.
{showConnectionModal && (
<WalletConnectionModal
setShowConnectionModal={setShowConnectionModal}
/>
)}
showConnectionModal gets set to true when a user clicks the “connect” button, but isn’t yet connected to the app.
It renders UserAccountDetail if the user’s wallet is connected. Wagmi has a hook called useAccount, which returns a boolean value isConnected. We can use the variable isConnected to show or hide things in our JSX code.
{isConnected && (
<UserAccountDetail
setShowUserAccountDetail={setShowUserAccountDetail}
showUserAccountDetail={showUserAccountDetail}
/>
)}
**handleShowConnectionModal**
This function gets called when a user isn’t yet connected, clicks the “connect” button, but hasn’t yet connected to a chosen wallet. This function changes the values of showConnectionModal and showUserAccountDetail. These 2 variables control the visibility of WalletConnectionModal and UserAccountDetail, respectively.
const handleShowConnectionModal = () => {
!isConnected
? setShowConnectionModal(true)
: setShowUserAccountDetail(!showUserAccountDetail);
};

This component will be displayed after a user clicks the “connect” button. It displays various wallets that a user can use to connect to the application.
Within the JSX code of WalletConnectionModal, there’s an unnamed function that loops over an array of connectors. connectors is an array containing all the wallets that users can connect to, such as MetaMask or Coinbase Wallet.
{connectors
.filter(
(connector) =>
connector.ready &&
// Don't show inject if it's MetaMask (we're already showing it)
!(connector.id === "injected" && connector.name === "MetaMask"),
)
.map((connector: Connector) => {
const isInjected = connector.id === "injected";
return (
<button
className="flex flex-row items-center rounded border border-gray-800 bg-gray-900 p-4 hover:bg-gray-800 disabled:cursor-not-allowed font-medium",
)}
disabled={!connector.ready}
onClick={() => connect({ connector })}
key={connector.id}
>
The primary aspect of the function involves a map function that iterates over the connectors array and renders each one onto its own button.. Within this function there’s extra logic that checks if it’s an “injected” connector. More on injected connectors in the next section.

Rabby is a competing wallet to MetaMask. It has more advanced features such as security warnings, and the ability to import multiple private keys into 1 installation. However, enabling Rabby presented some challenges that I’ll cover below.
What is an Injected Connector?
An injected connector refers to a user's default wallet. It's the wallet that a DApp will use if no other wallet is connected. If you're using Rabby, there's a switch you can toggle that sets it to your injected connector.


If you look again at the code in WalletConnectionModal, you’ll see 3 different things related to the injected connector:
A boolean value called injectedIsMetamask, which is a React state variable. This value gets set in a useEffect after checking whether or not Rabby wallet is active. If injectedIsMetaMask is true, Rabby will be shown instead of MetaMask on the connection modal.
A useEffect hook checking if the connecting wallet is using Rabby. Here’s the code used for that check:
useEffect(() => {
const rabbyConnector = connectors.find(
(connector) => connector.name.toLowerCase() === "rabby wallet",
);
if (rabbyConnector && !rabbyConnector.options.getProvider()._isRabby) {
// Rabby is forwarding to metamask
setInjectedIsMetaMask(true);
}
}, [connectors]);
Note that on the rabbyConnector object, if the getProvider method does not contain _isRabby, then we set the value is injectedIsMetaMask to be true.
In the JSX before the map function, we filter through the connectors array before looping over it with the map method. Here, we’re filtering to see if MetaMask is the injected wallet connector. It gets filtered out, because in our main.tsx component, we’re adding in MetaMask to our connectors array in the createConfig hook. (Scroll up the section “Main config hooks” to see that code snippet).
There’s another useEffect hook in this component:
useEffect(() => {
isConnected && setShowConnectionModal(false);
// close modal when WalletConnect or Coinbase modal is open
pendingConnector && setShowConnectionModal(false);
}, [isConnected, pendingConnector, setShowConnectionModal]);
This code was added after a small bug was discovered with WalletConnect, Coinbase Wallet, and any other wallet that uses its own modal.
When connecting to WalletConnect, we found that the WalletConnectionModal was overlaying:

The code snippet above fixed this bug, so WalletConnect (and Coinbase Wallet) rendered correctly like so:

This component is mostly for aesthetic purposes. There are 2 functional aspects worth mentioning:
Disconnect function: This utilizes the Wagmi hook useDisconnect. Here’s the code: const { disconnect } = useDisconnect();. Calling the disconnect function on the button will log out the user.
ENS Avatar: this is a nice touch if a user has an ENS name associated with an address. It builds familiarity and trust with the app. Here’s the code:
const { data: ensName } = useEnsName({ address, chainId: 1 });
const { data: avatarUrl } = useEnsAvatar({
name: ensName,
chainId: 1,
});
With this code in place, we can use avatarUrl (which is returned from the useEnsAvatar hook, to render a user’s avatar:

https://vimeo.com/877284150?share=copy
In this post we covered a technical explanation of how to implement a Web3 wallet connection using Wagmi hooks and React.
We explored key components such as the Main Config Hooks, Wallet Connection Component, and Wallet Connection Modal, each playing a vital role in creating a seamless and secure user experience within decentralized applications.
This demonstrates the simplicity of the implementation. Let me know if my explanation wasn’t simple enough, or what I can do to improve. Thanks for reading!
Behind the Scenes: Creating the AirSwap Member Dashboard App
Table of ContentsIntroductionWhat is the AirSwap Voter Rewards App?App Features I DevelopedMentorshipCode ReviewsTypeScriptWagmi LibraryCustom React ComponentsVariable NamingRegressionsLaunch DayPutting Apps into ProductionConclusionIntroductionIn this post, I'll share my experience and the key lessons I learned while building the AirSwap Member Dashboard app. This app provides users with the ability to stake AST tokens, vote on proposals that influence the AirSwap protocol, and claim re...

How to Build an Accordion Component
I've been actively involved in the frontend development of the new AirSwap Member Dashboard app. AirSwap currently leverages a platform named Activate for user stake management. However, within a month, Activate will be phased out, prompting the development of a new app for $AST token stakers. A notable feature of this app is the Accordion component, which I'll discuss here, illustrating its creation with React, Radix, and TailwindCSS.What is Radix-UI?Radix-UI logoRadix-UI is an ope...
My Experience as a Raid Guild Apprentice
My Experience as a Raid Guild Apprentice“If you want to go fast, go alone. If you want to go far, go together...”My journey as a software developer started about 15 months ago. Coming from a non-technical background in marketing, I didn't know many engineers. Knowing the right people won't make you smarter, but they can point you in the right direction and you'll learn more efficiently. Having a strong network of people is half the battle to success. In January, 2022 I started ...
Share Dialog
Share Dialog
Web Developer @ AirSwap // Building DeFi // React, TypeScript, Tailwind, Frontend Developer.

Subscribe to starrdev

Subscribe to starrdev
<100 subscribers
<100 subscribers
No activity yet