Setup
Initialize the project, install dependencies, and configure your development environment
Project Setup
We'll build this as a monorepo combining a Foundry smart contract project with a Next.js frontend.
Create Project Structure
mkdir rise-slots && cd rise-slotsInitialize Foundry Project
mkdir foundry-app && cd foundry-app
forge initThis creates the Foundry structure:
src/for contractstest/for testsscript/for deployment scriptsfoundry.tomlfor configuration
Install OpenZeppelin Contracts
We'll use OpenZeppelin's ERC20 implementation for the RCT token:
forge install OpenZeppelin/openzeppelin-contractsAdd to foundry.toml:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
remappings = ["@openzeppelin/=lib/openzeppelin-contracts/"]Initialize Next.js Project
Return to the root directory and create the Next.js app:
cd ..
bun create next-app@latest . --typescript --tailwind --appSelect the following 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.
Install Core Dependencies
Install the required packages for blockchain interaction:
bun add viem wagmi rise-wallet @tanstack/react-query shreds oxPackage breakdown:
viem: Ethereum library for contract interactionwagmi: React hooks for Ethereumrise-wallet: RISE Wallet connector with passkey support@tanstack/react-query: Async state management (required by wagmi)shreds: RISE's real-time event streaming libraryox: Cryptography library for session key P256 operations
Install UI Dependencies
bun add framer-motion class-variance-authority clsx tailwind-mergeThese provide:
framer-motion: Animations for spinning reels- Tailwind utility functions for styling
Project Structure
Your project should now look like this:
rise-slots/
├── foundry-app/
│ ├── src/
│ ├── test/
│ ├── script/
│ ├── lib/
│ │ └── openzeppelin-contracts/
│ └── foundry.toml
├── src/
│ └── app/
│ ├── page.tsx
│ ├── layout.tsx
│ └── providers.tsx (we'll create this)
├── package.json
└── next.config.tsConfiguration Files
Wagmi Configuration
Create src/config/wagmi.ts:
import { http, createConfig } from 'wagmi'
import { Chains, RiseWallet } from "rise-wallet"
import { riseWallet } from "rise-wallet/wagmi"
// RISE Wallet connector with default config (passkey-based)
export const rwConnector = riseWallet(RiseWallet.defaultConfig)
// Wagmi configuration for RISE Testnet
export const config = createConfig({
chains: [Chains.riseTestnet],
connectors: [rwConnector],
transports: {
[Chains.riseTestnet.id]: http("https://testnet.riselabs.xyz")
}
})
declare module 'wagmi' {
interface Register {
config: typeof config
}
}RISE Wallet uses passkeys for authentication - no seed phrases or private keys to manage! Users create an account with biometrics or a security key.
Provider Setup
Create src/app/providers.tsx:
"use client"
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config } from '@/config/wagmi'
import { ReactNode, useState } from 'react'
export function Providers({ children }: { children: ReactNode }) {
const [queryClient] = useState(() => new QueryClient())
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
)
}Update Root Layout
Modify src/app/layout.tsx:
import type { Metadata } from "next"
import { Providers } from "./providers"
import "./globals.css"
export const metadata: Metadata = {
title: "RISE Slots",
description: "Instant VRF-powered slot machine with gasless gameplay",
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<Providers>
{children}
</Providers>
</body>
</html>
)
}Constants Setup
Create src/constants/index.ts (we'll populate this after deploying contracts):
// Contract addresses (update after deployment)
export const SLOT_MACHINE_ADDRESS = "0x..." as const
export const RCT_TOKEN_ADDRESS = "0x..." as const
// Contract ABIs (we'll import these after compilation)
export const SLOT_MACHINE_ABI = [] as const
export const RCT_ABI = [] as constNext Steps
Your development environment is ready! Next, we'll write the smart contracts: an ERC20 token (RCT) and a VRF-powered slot machine.
Make sure you have some testnet ETH for deploying contracts. Get free testnet ETH from RISE Faucet.