DEV Community

Cover image for How to connect your frontend to Cosmos blockchain
Nur Fikri
Nur Fikri

Posted on

How to connect your frontend to Cosmos blockchain

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
Enter fullscreen mode Exit fullscreen mode

Install packages using pnpm

cd ./cosmos-frontend
pnpm install
pnpm dev
Enter fullscreen mode Exit fullscreen mode

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.tsx
import { 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

You'll have something like this:

preview

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
Enter fullscreen mode Exit fullscreen mode

Wrap our app with GrazProvider and set default chain to cosmoshub or what ever you like

// website/pages/_app.tsx
import { 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}>
+     <GrazProvider
+       grazOptions={{
+         defaultChain: mainnetChains.cosmoshub,
+       }}
+     >
        <Layout>
          <Component {...pageProps} />
        </Layout>
+     </GrazProvider>
    </ChakraProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.tsx
import { 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.tsx
import { 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Preview: https://cosmos-frontend-graz.vercel.app/

Top comments (2)

Collapse
 
bullishgopher profile image
Sandy Nguyen

Great work!
A quick question. May I know how you calculate the downloads?

Image description

Collapse
 
jonasand profile image
Jonas Andersen

Hi.
If you scaffold blockchain using IgniteCLI, it provides Vue wallet frontend.
It also supports to generate Vuex stores so it is very easy to go forward.