How to connect your frontend to Cosmos blockchain
Sep 26, 2022
Nur Fikri
First of all, to interact with cosmos ecosystem you need a wallet. You can find possible wallets available here. Keplr wallet is the most widely used wallet and their API integration is easy to use and is well-typed.
Install Keplr wallet extension to your browser and create an account if you haven't already registered.
Let's bootstrap a website using strangelove's starter template that already has typescript, eslint, prettier and chakra UI.
git clone <https://github.com/strangelove-ventures/strangestarter.git> cosmos-frontend
Install packages using pnpm
cd ./cosmos-frontendpnpm installpnpm dev
Okay now after we have our repo bootstrapped, letβs create a simple UI for connecting to a wallet and a dashboard.
// website/pages/index.tsximport { Box, Button, Center, HStack, Stack, Tag, TagLabel, TagLeftIcon, Text } from "@chakra-ui/react";export default function HomePage() {return (<Center minH="100vh"><Stack bgColor="whiteAlpha.100" boxShadow="md" maxW="md" p={4} rounded="md" spacing={4} w="full"><HStack><Tag><TagLeftIcon as={Box} bgColor="red.500" boxSize={3} rounded="full" /><TagLabel>Disconnected</TagLabel></Tag></HStack><Text>Active chain id: <b>Chain</b></Text><Text>Name: <b>Kiki</b></Text><Text noOfLines={1} wordBreak="break-all">Address: <b>...</b></Text><HStack align="end" pt={4}><Button>Connect Wallet</Button></HStack></Stack></Center>);}
You'll have something like this:
To use Keplr's API you can reference their API documentation. We need to manage the states, like if user already connected, create offlineSigner and other complex states.
Luckily Strangelove created a package called graz that abstracts the complexity of the Keplr API and wraps it into React hooks. From the documentation website it has features like:
πͺ 20+ hooks for interfacing with wallets, clients, signers, etc. (connecting, view balances, send tokens, etc.)
π³ Multiple wallet supports (Keplr & Leap wallet)
βοΈ Generate mainnet & testnet ChainInfo
π Built-in caching, request deduplication, and all the good stuff from @tanstack/react-query and zustand
π Auto refresh on wallet and network change
π Fully typed and tree-shakeable
So let's install graz to our project
pnpm website install graz
Wrap our app with GrazProvider and set default chain to cosmoshub or what ever you like
// website/pages/_app.tsximport { ChakraProvider } from "@chakra-ui/react";import type { AppProps } from "next/app";import { theme } from "styles/theme";import { Layout } from "ui/layout";import { GrazProvider, mainnetChains } from "graz";export default function CustomApp({ Component, pageProps }: AppProps) {return (<ChakraProvider resetCSS theme={theme}><GrazProvidergrazOptions={{defaultChain: mainnetChains.cosmoshub,}}><Layout><Component {...pageProps} /></Layout></GrazProvider></ChakraProvider>);}
Connect and disconnect
graz provides a mutation hook that we can use to connect and disconnect so you don't need to maintain the logic of these functions, simply use useConnect() and useDisconnect() to have connecting functionality.
To check if the user is already connected or not graz has a hook called useAccount(). One of the return objects is isConnected.
// website/pages/index.tsximport { Box, Button, Center, HStack, Stack, Tag, TagLabel, TagLeftIcon, Text } from "@chakra-ui/react";import { useAccount, useConnect, useDisconnect } from "graz";export default function HomePage() {const { isConnected } = useAccount();const { connect } = useConnect();const { disconnect } = useDisconnect();return (<Center minH="100vh"><Stack bgColor="whiteAlpha.100" boxShadow="md" maxW="md" p={4} rounded="md" spacing={4} w="full"><HStack><Tag><TagLeftIcon as={Box} bgColor={isConnected ? "green.500" : "red.500"} boxSize={3} rounded="full" /><TagLabel>{isConnected ? "Connected" : "Disconnected"}</TagLabel></Tag></HStack><Text>Active chain id: <b>Chain</b></Text><Text>Name: <b>Kiki</b></Text><Text noOfLines={1} wordBreak="break-all">Address: <b>...</b></Text><HStack align="end" pt={4}><Button onClick={() => (isConnected ? disconnect() : connect())}>{isConnected ? "Disconnect" : "Connect Wallet"}</Button></HStack></Stack></Center>);}
Show connected information
After we have connection functionality, we should display the connection information. We can get the connected account information from useAccount() and the current active chain from useActiveChain().
// website/pages/index.tsximport { Box, Button, Center, HStack, Stack, Tag, TagLabel, TagLeftIcon, Text } from "@chakra-ui/react";import { useAccount, useActiveChain, useConnect, useDisconnect } from "graz";export default function HomePage() {const { isConnected, data: account } = useAccount();const { connect } = useConnect();const { disconnect } = useDisconnect();const activeChain = useActiveChain();return (<Center minH="100vh"><Stack bgColor="whiteAlpha.100" boxShadow="md" maxW="md" p={4} rounded="md" spacing={4} w="full"><HStack><Tag><TagLeftIcon as={Box} bgColor={isConnected ? "green.500" : "red.500"} boxSize={3} rounded="full" /><TagLabel>{isConnected ? "Connected" : "Disconnected"}</TagLabel></Tag></HStack><Text>Active chain id: <b>{activeChain?.chainId}</b></Text><Text>Name: <b>{account?.name}</b></Text><Text noOfLines={1} wordBreak="break-all">Address: <b>{account?.bech32Address}</b></Text><HStack align="end" pt={4}><Button onClick={() => (isConnected ? disconnect() : connect())}>{isConnected ? "Disconnect" : "Connect Wallet"}</Button></HStack></Stack></Center>);}
Congratulations now your app is connected to the cosmos ecosystem
When you connect with graz's useConnect() it automatically generates offlineSigners, Clients, SigningClients. You can get the details from useOfflineSigners(), useClients() and useSigningClients() if you want to interact with those things.
graz has many useful hooks such as useBalances() to view balances, useSendTokens() to send tokens, useBalanceStaked() to see how many tokens are staked, and many more! You can see it on the documentation https://graz.strange.love
Source code: https://github.com/codingki/cosmos-frontend