Setup
Project setup, configuration, and UI components
Project Setup
Create a New Next.js Project
First, create a new Next.js application with TypeScript:
npx create-next-app@latest rise-wallet-appyarn create next-app rise-wallet-apppnpm create next-app rise-wallet-appbun create next-app rise-wallet-appWhen prompted, select these options:
- Use recommended Next.js defaults: No, customize settings
- TypeScript: Yes
- Linter: None
- React Compiler: Yes
- Tailwind CSS: Yes
src/directory: Yes- App Router: Yes
- Customize import alias: No
If you've completed another tutorial, you can select No, reuse previous settings to skip configuration.
Navigate into your project:
cd rise-wallet-appInstall Dependencies
Install the required packages for wallet integration:
npm install rise-wallet wagmi viem @tanstack/react-queryyarn add rise-wallet wagmi viem @tanstack/react-querypnpm add rise-wallet wagmi viem @tanstack/react-querybun add rise-wallet wagmi viem @tanstack/react-queryPackage breakdown:
rise-wallet- RISE Wallet SDK with wagmi connectorwagmi- React hooks for Ethereum wallet connectionsviem- Low-level library for transactions and contract interactions@tanstack/react-query- Server state management for async operations
Configuration
Set Up Wagmi Config
Create a wagmi configuration file to connect to RISE Testnet:
import { Chains, RiseWallet, riseWallet } from "rise-wallet";
import { createConfig, http } from "wagmi";
export const config = createConfig({
chains: [Chains.riseTestnet],
connectors: [riseWallet(RiseWallet.defaultConfig)],
transports: {
[Chains.riseTestnet.id]: http("https://testnet.riselabs.xyz"),
},
});
declare module "wagmi" {
interface Register {
config: typeof config;
}
}This configuration:
- Targets RISE Testnet as the only chain
- Uses the RISE Wallet connector
- Sets up HTTP RPC transport for testnet
Create Provider Component
Create a provider to wrap your app with wagmi and React Query:
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { type ReactNode, useState } from "react";
import { WagmiProvider } from "wagmi";
import { config } from "@/config/wagmi";
export function Provider(props: { children: ReactNode }) {
const [queryClient] = useState(() => new QueryClient());
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{props.children}
</QueryClientProvider>
</WagmiProvider>
);
}Update Root Layout
Wrap your application with the provider in the root layout:
import type { Metadata } from "next";
import "./globals.css";
import { Provider } from "./provider";
export const metadata: Metadata = {
title: "RISE Wallet Quickstart",
description: "Learn how to integrate RISE Wallet with passkey and session key flows",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Provider>{children}</Provider>
</body>
</html>
);
}Define Contract Constants
Create a constants file with contract addresses and ABIs:
export const SIMPLE_TOKEN_ADDRESS = "0x2Fe6B2b6e895fc0Ad192A249C3240685Ecbb177C";
export const COUNTER_ADDRESS = "0xD38794596a78A0E446a8A61d9d04466118b30809";
export const SIMPLE_TOKEN_ABI = [
{
type: "function",
name: "mint",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
name: "transfer",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ name: "", type: "bool" }],
stateMutability: "nonpayable",
},
{
type: "function",
name: "balanceOf",
inputs: [{ name: "account", type: "address" }],
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
},
] as const;
export const COUNTER_ABI = [
{
type: "function",
name: "increment",
inputs: [],
outputs: [],
stateMutability: "nonpayable",
},
{
type: "function",
name: "count",
inputs: [],
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
},
] as const;These contracts are already deployed on RISE Testnet for testing purposes. Feel free to deploy your own, using the previous two tutorials!
Building the UI Components
Create a Wallet Button
Build a reusable button component for connecting/disconnecting the wallet:
"use client";
import { useEffect, useState } from "react";
import { useConnect, useConnection, useDisconnect } from "wagmi";
export function WalletButton() {
const [mounted, setMounted] = useState(false);
const [copied, setCopied] = useState(false);
const { address, connector } = useConnection();
const { connect, connectors } = useConnect();
const { disconnect } = useDisconnect();
useEffect(() => {
setMounted(true);
}, []);
const handleCopy = async () => {
if (address) {
await navigator.clipboard.writeText(address);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
if (!mounted) return null;
if (address && connector) {
return (
<div className="flex items-center gap-2">
<button
onClick={handleCopy}
className="px-4 py-2 bg-gray-800 text-white rounded-lg hover:bg-gray-700 transition-colors"
>
{copied
? "Copied!"
: `${address.slice(0, 6)}...${address.slice(-4)}`}
</button>
<button
onClick={() => disconnect()}
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
>
Disconnect
</button>
</div>
);
}
return (
<button
onClick={() => connect({ connector: connectors[0] })}
className="px-6 py-3 bg-green-500 text-white font-semibold rounded-lg hover:bg-green-600 transition-colors"
>
Connect Wallet
</button>
);
}Key features:
- Shows truncated address when connected
- Copy address to clipboard functionality
- Disconnect button
- Hydration-safe rendering (prevents SSR mismatches)
Create a Navigation Bar
Build a navbar to navigate between flows:
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { WalletButton } from "./WalletButton";
export function Navbar() {
const pathname = usePathname();
return (
<nav className="border-b border-gray-800 bg-black">
<div className="max-w-6xl mx-auto px-4 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-6">
<Link href="/" className="text-xl font-bold text-green-500">
RISE Wallet
</Link>
<div className="flex gap-4">
<Link
href="/passkey"
className={`px-3 py-2 rounded-lg transition-colors ${
pathname === "/passkey"
? "bg-green-500 text-white"
: "text-gray-400 hover:text-white"
}`}
>
Passkey Flow
</Link>
<Link
href="/session"
className={`px-3 py-2 rounded-lg transition-colors ${
pathname === "/session"
? "bg-green-500 text-white"
: "text-gray-400 hover:text-white"
}`}
>
Session Key Flow
</Link>
</div>
</div>
<WalletButton />
</div>
</div>
</nav>
);
}Create a Home Page
Build a landing page with flow selection cards:
"use client";
import Link from "next/link";
import { Navbar } from "@/components/Navbar";
import { useConnection } from "wagmi";
import { useEffect, useState } from "react";
export default function Home() {
const [mounted, setMounted] = useState(false);
const { address } = useConnection();
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) return null;
return (
<div className="min-h-screen bg-black text-white">
<Navbar />
<div className="max-w-4xl mx-auto px-4 py-16">
<div className="text-center mb-12">
<h1 className="text-5xl font-bold mb-4 text-green-500">
RISE Wallet Quickstart
</h1>
<p className="text-xl text-gray-400">
Choose a transaction signing pattern to get started
</p>
</div>
{address ? (
<div className="grid md:grid-cols-2 gap-6">
<Link
href="/passkey"
className="p-8 bg-gray-900 rounded-xl border border-gray-800 hover:border-green-500 transition-all group"
>
<div className="text-4xl mb-4">🔐</div>
<h2 className="text-2xl font-bold mb-2 group-hover:text-green-500">
Passkey Flow
</h2>
<p className="text-gray-400">
Direct transaction signing with wallet approval popups for each action
</p>
</Link>
<Link
href="/session"
className="p-8 bg-gray-900 rounded-xl border border-gray-800 hover:border-green-500 transition-all group"
>
<div className="text-4xl mb-4">⏱️</div>
<h2 className="text-2xl font-bold mb-2 group-hover:text-green-500">
Session Key Flow
</h2>
<p className="text-gray-400">
Background signing with pre-authorized permissions for seamless UX
</p>
</Link>
</div>
) : (
<div className="text-center">
<p className="text-gray-400 mb-6">
Connect your wallet to explore transaction flows
</p>
</div>
)}
</div>
</div>
);
}Now you have all the basic setup complete. In the next sections, you'll implement the passkey and session key flows.