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:
'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:
'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):
export * from './Providers'
Now, edit file src/app/layout.tsx
:
- add rainbowkit css
import '@rainbow-me/rainbowkit/styles.css'
- get stored values for
initialChainId
andinitialLiveState
from cookies - add created
Providers
component and provide initial values
So code will be:
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
'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
:
'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
export * from './Providers'
export * from './Header'
And use in global layout - 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, 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:
- AzuroSDKProvider: Understand its role in the app.