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:
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.