Skip to content

NextJS Frontend Setup

The NextJS App

The NextJS app was built from a rainbowkit template. It is pre-configured using several different chains and basic CSS. First, we're going to change the config for the chains, then we'll install Tailwind (which is optional), then we're adding the dd-abstractionkit to send off data-dependent User Operations, then we're dealing with the smart wallets and finally we're interacting with our NFT contract.

Let's get started!

Adjusting the Chains

First thing is to adjust that only polygon is in the selectable chains. With this, the chain selector will automatically disappear all together.

Open src/wagmi.ts and remove all chains where you did not deploy the contracts to. In the case of this tutorial we deploy to Polygon, but your chains might differ, so take this as a template:

import { getDefaultConfig } from '@rainbow-me/rainbowkit';
import {
  polygon,
} from 'wagmi/chains';

export const config = getDefaultConfig({
  appName: 'RainbowKit App',
  projectId: 'YOUR_PROJECT_ID',
  chains: [
    polygon,
  ],
  ssr: true,
});

Next we're working on the layout of the app. I like to use Tailwind for this example, which is optional to add.

Adding Tailwind and adjusting the Layout (optional)

If we follow this guide its fairly easy to install Tailwind: https://tailwindcss.com/docs/guides/nextjs.

First we install the tailwind packages:

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

Since we use the src folder, we update our tailwind.config.js file:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    // Or if using `src` directory:
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Then change the styles/globals.css to:

@tailwind base;
@tailwind components;
@tailwind utilities;

Delete the styles/Home.module.css file:

rm styles/Home.modules.css

And change the src/pages/index.tsx so that it just is barebone with the right classes for tailwind to center the content:

import { ConnectButton } from '@rainbow-me/rainbowkit';
import type { NextPage } from 'next';
import Head from 'next/head';

const Home: NextPage = () => {

  return (
    <div className='container ms-auto text-center'>
      <Head>
        <title>Oracle Demo</title>
        <meta
          content="Oracle Demo"
          name="description"
        />
        <link href="/favicon.ico" rel="icon" />
      </Head>

      <h1 className="text-center my-6 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl lg:text-6xl">
        Mint a Silver NFT.
      </h1>
      <h3 className='text-center mb-1 text-lg font-normal text-gray-500 lg:text-xl sm:px-16 xl:px-48 dark:text-gray-400'>Prices provided by the <a href="https://oracle.morpher.com" className='underline'>Morpher Oracle</a></h3>
      <h3 className='text-center mb-6 text-lg font-normal text-gray-500 lg:text-xl sm:px-16 xl:px-48 dark:text-gray-400'>+ <a href="https://www.npmjs.com/package/@morpher-io/dd-abstractionkit" className='underline'>Data Dependend-Abstraction Kit</a>.</h3>

      <div className='flex flex-row justify-between my-6' >
        <div></div>
        <ConnectButton />
        <div></div>
      </div>



      <footer>
        <a href="https://rainbow.me" rel="noopener noreferrer" target="_blank">
          Made with ❤️ by your frens at 🌈
        </a>
      </footer>
    </div>
  );
};

export default Home;

This should give you this result:

Starting point our NFT Website
Starting point our NFT Website

Adding in missing npm packages

For our Oracle to work, we need to rely on On-Chain wallets. In our case, we use Candide ERC4337 Wallets to generate the Safe Wallet address. We forked Abstraction-Kit and enhanced it with a separate call to an "oracle enabled" bundler.

Install our DD-Abstractionkit fork with

npm install @morpher-io/dd-abstractionkit

Before we calculate the Smart Account Address, let's add some icons.

Adding the Icons (optional)

In this (optional) step, you can use the following icons if you want to follow along this tutorial. It's 3 SVG icons, the coins are actually generated by chatGPT as SVG with minor corrections and the Money icon is from the Flowbite Icon Library

Add the following file to const/icons.tsx:

type IconProps = React.HTMLAttributes<SVGElement>

export const Icons = {
    goldCoin: (props: IconProps) => (<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" className={props.className} preserveAspectRatio="xMidYMid meet">


        <circle cx="100" cy="100" r="90" fill="gold" stroke="#d4af37" strokeWidth="10" />

        <circle cx="100" cy="100" r="60" fill="none" stroke="rgba(255, 255, 255, 0.6)" strokeWidth="5" />

        <text x="50%" y="50%" textAnchor="middle" fill="#d4af37" font-size="50" fontFamily="Arial" dy=".35em">Au</text>
      </svg>

    ),
    silverCoin: (props: IconProps) => (<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" className={props.className} preserveAspectRatio="xMidYMid meet">
        <circle cx="100" cy="100" r="90" fill="silver" stroke="#b0b0b0" strokeWidth="10" />
        <circle cx="100" cy="100" r="60" fill="none" stroke="rgba(255, 255, 255, 0.6)" strokeWidth="5" />
        <text x="50%" y="50%" textAnchor="middle" fill="#b0b0b0" fontSize="50" fontFamily="Arial" dy=".35em">Ag</text>
      </svg>


    ),

    iconCash: (props: IconProps) => (<svg className="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
        <path stroke="currentColor" strokeLinecap="round" strokeWidth="2" d="M8 7V6a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-1M3 18v-7a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1Zm8-3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z"/>
      </svg>
      )
}

You can use this for example in the index.tsx page when a user is connected:

import { ConnectButton } from '@rainbow-me/rainbowkit';
import type { NextPage } from 'next';
import Head from 'next/head';

import { useAccount } from 'wagmi';
import { Icons } from '../const/icons';

const Home: NextPage = () => {

  const { isConnected } = useAccount();

  return (
    <div className='container ms-auto text-center'>
 ...

      {isConnected && <>
        <div className='flex justify-center mb-6'>
          <Icons.silverCoin className='w-20 h-20' />
        </div>
        </>
      }
...

If you toggle the account connection you will see the Icon appear and disappear.

Let's get back to the important part, the calculation of the Safe Wallet Account.