Skip to main content

Scaffold

npx create-inco-app@latest my-app --wallet rainbowkit --framework hardhat --chain evm --yes

Environment Setup

Get your WalletConnect project ID from cloud.walletconnect.com and add it to frontend/.env.local:
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here
NEXT_PUBLIC_CONFLOTTERY_ADDRESS=<deployed_contract_address>
Without a WalletConnect project ID, the app falls back to a basic wagmi config with injected wallets only (MetaMask, etc.).

Provider Setup

RainbowKit uses getDefaultConfig() for convenient setup when a WalletConnect project ID is available, and wraps the app with RainbowKitProvider for the connect modal UI.
Providers.tsx
"use client";

import { ReactNode, useState, useEffect } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider, createConfig, http } from "wagmi";
import {
  getDefaultConfig,
  RainbowKitProvider,
  darkTheme,
  lightTheme,
} from "@rainbow-me/rainbowkit";
import { ThemeProvider, useTheme } from "next-themes";
import { baseSepolia } from "wagmi/chains";

const queryClient = new QueryClient();

const projectId = process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "";

const config = projectId
  ? getDefaultConfig({
      appName: "inco confidential lottery",
      projectId,
      chains: [baseSepolia],
      ssr: true,
    })
  : createConfig({
      chains: [baseSepolia],
      transports: {
        [baseSepolia.id]: http(),
      },
      ssr: true,
    });

const RainbowKitWithTheme = ({ children }: { children: ReactNode }) => {
  const { resolvedTheme } = useTheme();
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  const rainbowTheme =
    mounted && resolvedTheme === "light"
      ? lightTheme({ accentColor: "#262626", accentColorForeground: "#fafafa", borderRadius: "none" })
      : darkTheme({ accentColor: "#d4d4d4", accentColorForeground: "#0a0a0a", borderRadius: "none" });

  return (
    <RainbowKitProvider theme={rainbowTheme}>{children}</RainbowKitProvider>
  );
};

const Providers = ({ children }: { children: ReactNode }) => {
  return (
    <ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
      <WagmiProvider config={config}>
        <QueryClientProvider client={queryClient}>
          <RainbowKitWithTheme>{children}</RainbowKitWithTheme>
        </QueryClientProvider>
      </WagmiProvider>
    </ThemeProvider>
  );
};

export { Providers };
Provider hierarchy: ThemeProviderWagmiProviderQueryClientProviderRainbowKitProvider RainbowKit sits on top of wagmi and provides a pre-built connect modal with wallet discovery. The RainbowKitWithTheme wrapper syncs the modal theme with your app’s dark/light mode.

Inco SDK Integration

The Inco SDK works with the walletClient provided by wagmi (which RainbowKit manages). Here’s the core pattern:
useConfLottery.ts
import { Lightning } from "@inco/js/lite";
import { handleTypes } from "@inco/js";
import { useAccount, useWalletClient, useWriteContract } from "wagmi";
import { parseEther } from "viem";

// Initialize Inco once
const zap = await Lightning.latest("testnet", 84532);

// Encrypt a value before sending on-chain
const { address } = useAccount();
const { data: walletClient } = useWalletClient();

async function deposit(amount: string) {
  const ciphertext = await zap.encrypt(parseEther(amount), {
    accountAddress: address,
    dappAddress: LOTTERY_ADDRESS,
    handleType: handleTypes.euint256,
  });

  const fee = await publicClient.readContract({
    address: zap.executorAddress,
    abi: getFeeAbi,
    functionName: "getFee",
  });

  writeContract({
    address: LOTTERY_ADDRESS,
    abi: confLotteryAbi,
    functionName: "deposit",
    args: [ciphertext],
    value: fee,
  });
}

// Decrypt with attestation
async function checkWinner() {
  const encryptedHandle = await publicClient.readContract({
    address: LOTTERY_ADDRESS,
    abi: confLotteryAbi,
    functionName: "getMyWinnerCheck",
    args: [currentRound],
    account: address,
  });

  const result = await zap.attestedDecrypt(walletClient, [encryptedHandle]);
  const isWinner = result[0].plaintext.value; // true or false
}
RainbowKit manages the wallet connection — once connected, wagmi’s useWalletClient() provides the signer that Inco’s attestedDecrypt uses for signing attestation requests.

Dependencies

PackagePurpose
@rainbow-me/rainbowkitWallet connect UI & management
@inco/jsInco encryption/decryption
wagmiEVM wallet hooks
viemEthereum utilities