Developer Hub
🔮 For applications
Guides & Tutorials
Tutorial: build your dApp
Step 2: Prepare to Connect User Wallets

Prepare to Connect User Wallets

Preparation

In the blockchain world, Web3 wallets are essential. They let you log into apps and interact with the blockchain. You can also sign and execute transactions safely.

Get Started with Connection Libraries

  • Why Use Them? These libraries make the process easier.
  • First Step: Start by adding @rainbow-me/rainbowkit. Just run:
npm install @rainbow-me/rainbowkit

Connecting Your Wallet to dApps

  • Why WalletConnect? It's a go-to standard for linking your wallet to dApps.
  • Your Action Item: Register on walletconnect.com and get your unique Project ID. This ID is a must, no matter which library you use.

Go to walletconnect.com and get own projectId (opens in a new tab)

Remember, connecting your wallet to dApps is crucial for secure and efficient interactions in the blockchain space. Keep it straightforward and you'll be set to go! 🌟

Setup

Web3 connect configs

The first thing you need to do is set up Wagmi providers and wrap your whole App. Here we'll set up working chains and connecting lib. Let's create new component src/components/Providers.tsx and add required imports and config for wagmi:

src/components/Providers.tsx
'use client'
 
import React from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { RainbowKitProvider, getDefaultWallets, getDefaultConfig } from '@rainbow-me/rainbowkit'
import { WagmiProvider } from 'wagmi'
import { polygon, gnosis } from 'viem/chains'
 
 
const { wallets } = getDefaultWallets()
 
const chains = [
  polygon,
  gnosis,
] as const
 
const wagmiConfig = getDefaultConfig({
  appName: 'Azuro',
  appIcon: 'https://path-to-your-icon.com/icon.png',
  projectId: '2f82a1608c73932cfc64ff51aa38a87b', // get your own project ID - https://cloud.walletconnect.com/sign-in
  wallets,
  chains,
})
 
const queryClient = new QueryClient()
 
type ProvidersProps = {
  children: React.ReactNode
}
 
export function Providers(props: ProvidersProps) {
  const { children } = props
 
  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <RainbowKitProvider>
          {children}
        </RainbowKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Great. Now your app can handle web3 connections. We’ll see how to add a “Connect” button later.

Azuro providers setup

After base web3 connect setup, let's add azuro SDK provider.

Let's add them, so final code of Providers component will be:

src/components/Providers.tsx
'use client'
 
import React from 'react'
import { AzuroSDKProvider, LiveProvider, ChainId } from '@azuro-org/sdk'
import { RainbowKitProvider, getDefaultWallets, getDefaultConfig } from '@rainbow-me/rainbowkit'
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { polygon, gnosis } from 'viem/chains'
 
 
const { wallets } = getDefaultWallets()
 
const chains = [
  polygon,
  gnosis,
] as const
 
const wagmiConfig = getDefaultConfig({
  appName: 'Azuro',
  appIcon: 'https://path-to-your-icon.com/icon.png',
  projectId: '2f82a1608c73932cfc64ff51aa38a87b', // get your own project ID - https://cloud.walletconnect.com/sign-in
  wallets,
  chains,
})
 
const queryClient = new QueryClient()
 
type ProvidersProps = {
  children: React.ReactNode
  initialChainId?: string
  initialLiveState?: boolean
}
 
export function Providers(props: ProvidersProps) {
  const { children, initialChainId, initialLiveState } = props
 
  const chainId = initialChainId
    ? chains.find(chain => chain.id === +initialChainId) ? +initialChainId as ChainId : polygon.id
    : polygon.id
 
  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <RainbowKitProvider>
          <AzuroSDKProvider initialChainId={chainId}>
            <LiveProvider initialLiveState={initialLiveState}>
              {children}
            </LiveProvider>
          </AzuroSDKProvider>
        </RainbowKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Use Providers in global layout

Now our Providers component is ready to be used in the app. Let's do it. To make things easier, let's create index.ts file in src/components and re-export component (later do it with all the components we create):

src/components/index.ts
export * from './Providers'
 

Now, edit file src/app/layout.tsx:

  • add rainbowkit css import '@rainbow-me/rainbowkit/styles.css'
  • get stored values for initialChainId and initialLiveState from cookies
  • add created Providers component and provide initial values

So code will be:

src/app/layout.tsx
import type { Metadata } from 'next'
import { cookies } from 'next/headers'
import { Inter } from 'next/font/google'
import './globals.css'
import '@rainbow-me/rainbowkit/styles.css'
import { Providers } from '@/components'
 
const inter = Inter({ subsets: ['latin'] })
 
export const metadata: Metadata = {
  title: 'Azuro Betting App',
}
 
export default function RootLayout(props: { children: React.ReactNode }) {
  const { children } = props
  const cookieStore = cookies()
 
  const initialChainId = cookieStore.get('appChainId')?.value
  const initialLiveState = JSON.parse(cookieStore.get('live')?.value || 'false')
 
  return (
    <html lang="en">
      <body className={inter.className}>
        <Providers initialChainId={initialChainId} initialLiveState={initialLiveState}>
          <main className="container pt-5 pb-10">
            {children}
          </main>
        </Providers>
      </body>
    </html>
  )
}

Page Layout

To show active link in navigation, let's add small helping component "ActiveLink". It's just a wrapper of Next.JS Link but handles active state. Create component src/components/ActiveLink.tsx

src/components/ActiveLink.tsx
'use client'
import React, { useState, useEffect } from 'react'
import { usePathname } from 'next/navigation'
import Link, { LinkProps } from 'next/link'
 
 
type ActiveLinkProps = LinkProps & {
  className?: string
  activeClassName: string
  regex?: string
}
 
export const ActiveLink: React.FC<React.PropsWithChildren<ActiveLinkProps>> = (props) => {
  const { children, className, activeClassName, regex, ...rest } = props
 
  const activePathname = usePathname()
  const [ computedClassName, setComputedClassName ] = useState(className)
 
  useEffect(() => {
    // Dynamic route will be matched via props.as
    // Static route will be matched via props.href
    const linkPathname = new URL(
      (rest.as || rest.href) as string,
      location.href
    ).pathname
 
    const isMatch = regex ? new RegExp(regex).test(activePathname) : activePathname === linkPathname
 
    const newClassName = isMatch
      ? `${className} ${activeClassName}`.trim()
      : className
 
    if (newClassName !== computedClassName) {
      setComputedClassName(newClassName)
    }
  }, [
    activePathname,
    rest.as,
    rest.href,
    activeClassName,
    className,
  ])
 
  return (
    <Link className={computedClassName} {...rest}>
      {children}
    </Link>
  )
}
⚠️

Don't forget to add export to src/components/index.ts.

Let's add a header with top-level navigation, "Connect" button and auto-reconnect (to keep connection after page reload). Create component src/components/Header.tsx:

src/components/Header.tsx
'use client'
 
import { ConnectButton } from '@rainbow-me/rainbowkit'
import { ActiveLink } from '@/components'
 
 
export function Header() {
 
  return (
    <header className="flex items-center py-3.5 border-b border-zinc-200">
      <div className="text-xl font-semibold">Azuro Betting</div>
      <div className="flex ml-10">
        <ActiveLink
          className="text-zinc-500 hover:text-black transition"
          activeClassName="!text-black font-semibold !cursor-default"
          href="/events/top"
          regex="^\/events\/[^/]+?$"
        >
          Events
        </ActiveLink>
        <ActiveLink
          className="text-zinc-500 hover:text-black transition ml-4"
          activeClassName="!text-black font-semibold !cursor-default"
          href="/bets"
          regex="^\/bets"
        >
          Bets
        </ActiveLink>
      </div>
      <div className="ml-auto flex items-center">
        <ConnectButton chainStatus="none" />
      </div>
    </header>
  )
}

Add export to src/components/index.ts

src/components/index.ts
export * from './Providers'
export * from './Header'

And use in global layout - src/app/layout.tsx:

src/components/index.ts
import type { Metadata } from 'next'
import { cookies } from 'next/headers'
import { Inter } from 'next/font/google'
import './globals.css'
import '@rainbow-me/rainbowkit/styles.css'
import { Providers, Header } from '@/components'
 
const inter = Inter({ subsets: ['latin'] })
 
export const metadata: Metadata = {
  title: 'Azuro Betting App',
}
 
export default function RootLayout(props: { children: React.ReactNode }) {
  const { children } = props
  const cookieStore = cookies()
 
  const initialChainId = cookieStore.get('appChainId')?.value
  const initialLiveState = JSON.parse(cookieStore.get('live')?.value || 'false')
 
  return (
    <html lang="en">
      <body className={inter.className}>
        <Providers initialChainId={initialChainId} initialLiveState={initialLiveState}>
          <Header />
          <main className="container pt-5 pb-10">
            {children}
          </main>
        </Providers>
      </body>
    </html>
  )
}

Great! Run the following command

npm run dev

This starts your Next.js app’s "development server" on port 3000. Let’s check to see if it’s working. And visit localhost:3000 (opens in a new tab) and ensure that the Connect Button is present and functioning properly.

Learn more

In this tutorial, we're crafting a simple betting app. Are you eager to explore more? Then delve deeper into some key elements of the SDK used in this section: