Part 1 - Connect Wallet using Metamask and mint an NFT

This 2-part tutorial will guide you through integrating with Bastion SDK in your Next.js app through Metamask and then using social login via Particle Auth.

This is Part 1 of the tutorial.

Note: You can find the complete code for this app in this Github repo.

Prerequisites

  1. Node.js and npm installed

  2. Basic understanding of Next.js and React

  3. A Bastion account for API key

  4. A Particle Network account

Step 1: Set Up Your Next.js Project

If you haven't already set up a Next.js project, create one by running:

npx create-next-app nextjs-demo-app

Make sure that you choose the following options for this demo to work. (It should still work with different options, but the project structure would be different).

Note:- If you're using App Router in NextJS 13, you should use /app/index.tsx instead of /pages/index.tsx

Navigate into your project folder:

cd nextjs-demo-app

Step 2: Install Required Packages

Install the required npm packages:

npm install bastion-wallet-sdk ethers@5 next @particle-network/auth @particle-network/provider

Step 3: Get Bastion API Key

  1. Log in to the Bastion Dashboard.

  2. Generate a new API key.

Step 4: Add Environment Variables

Create a .env.local file at the root of your Next.js project and add the following:

NEXT_PUBLIC_BASTION_API_KEY=<your_bastion_api_key>

Replace the placeholder values with your Bastion API key.

Step 5: Implement connect with Metamask and connect with Bastion

Add the following code to the file pages/index.tsx

// /pages/index.tsx

import { useState, useEffect } from "react";
import { ethers, Contract } from "ethers";
import { Bastion } from "bastion-wallet-sdk";

export default function Home() {
	const [address, setAddress] = useState<string>("");
	const [bastionConnect, setBastionConnect] = useState<any>();
	const [isMinting, setIsMinting] = useState<boolean>(false);
	const [userOpHash, setUserOpHash] = useState<string>("");

	useEffect(() => {
		if (window.ethereum) {
			window.ethereum.on("accountsChanged", (accounts: string[]) => {
				setAddress(accounts[0]);
			});
		}
	}, []);

	const loginWithMetamask = async () => {
		try {
			// Check if Metamask is installed
			if (!window.ethereum || !window.ethereum.isMetaMask) {
				alert("Please install Metamask.");
				return;
			}

			// Request account access
			const accounts = await window.ethereum.request({
				method: "eth_requestAccounts",
			});

			setAddress(accounts[0]);

			const tempProvider = new ethers.providers.Web3Provider(window.ethereum, "any");

			const bastion = new Bastion();
			const bastionConnect = await bastion.bastionConnect;

			await bastionConnect.init(tempProvider, {
				apiKey: process.env.NEXT_PUBLIC_BASTION_API_KEY || "",
			});

			setBastionConnect(bastionConnect);
		} catch (e) {
			console.error(e);
		}
	};

	const mintNFT = async () => {
		try {
			setIsMinting(true);
			const contractAddress = "0xEAC57C1413A2308cd03eF3CEa5c9224487825341";
			const contractABI = ["function safeMint(address to) public"];

			const nftContract = new Contract(contractAddress, contractABI, bastionConnect);

			const res = await nftContract.safeMint(address);
			console.log(res);
			setIsMinting(false);
			setUserOpHash(res.hash);
		} catch (e) {
			console.error(e);
		}
	};

	return (
		<div>
			{address ? (
				<div>
					<h1>Welcome to Bastion!</h1>
					<h4>Logged in as {address}</h4>
					{isMinting && <h3>Minting...</h3>}
					{userOpHash && <h3>Minted NFT! User Operation Hash: {userOpHash}</h3>}
					<button onClick={mintNFT} className="rounded-2 bg-gradient-to-r from-[#6C1EB0] to-[#DE389F] mx-4 my-4 px-10 py-4 h-full rounded-xl">
						Mint NFT
					</button>
				</div>
			) : (
				<div>
					<h1>Welcome to Bastion!</h1>
					<button onClick={loginWithMetamask} className="rounded-2 bg-gradient-to-r from-[#6C1EB0] to-[#DE389F] mx-4 my-4 px-10 py-4 h-full rounded-xl">
						Login with Metamask
					</button>
				</div>
			)}
		</div>
	);
}

Step 6: Add CSS

Go to your globals.css file, which is usually under /styles.

Add the following CSS at the bottom -

/* styles/globals.css */

html, body {
  max-width: 100vw;
  overflow-x: hidden;
  height: 100vh;  /* New: Set height to full viewport height */
}

/* Reset some default browser styles */
body, h1, button {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

/* Make a container for the whole page */
div {
  text-align: center;
  margin: 0 auto; /* Updated: Removed top and bottom margin */
  height: 100vh;  /* New: Set height to full viewport height */
  display: flex;
  flex-direction: column;
  justify-content: center;  /* Center content vertically */
  align-items: center;  /* Center content horizontally */
}

/* Add some padding and a background gradient to buttons */
button {
  padding: 15px 25px;
  font-size: 16px;
  cursor: pointer;
  border: none;
  border-radius: 4px;
  color: #fff;
  background: linear-gradient(to right, #6C1EB0, #DE389F);
  transition: 0.3s ease-out;
  margin-top: 15px;
}

h3{
  margin-top: 15px;
}

.main-container {
  text-align: center;
  height: 100vh;  /* Set height to full viewport height */
  display: flex;
  flex-direction: column;
  justify-content: center;  /* Center content vertically */
  align-items: center;  /* Center content horizontally */
}

/* Hover effect for buttons */
button:hover {
  background: linear-gradient(to right, #DE389F, #6C1EB0);
}

/* Add some spacing between items */
h1, h2, h3, button {
  margin-bottom: 20px;
}

Step 7: Test your app

Now you can run your app using

npm run dev

Navigate to http://localhost:3000 and click on the "Login with Metamask" button. Follow the usual Metamask login procedure, and you should see your Ethereum address displayed on the screen, indicating a successful login.

You should also see a Mint NFT button on the page now. If you click on this button, the app will mint an NFT to your Smart Wallet by sending a User Operation on the Arbitrum Goerli testnet using the Pimlico bundler.

That's it! You've successfully integrated Metamask with the Bastion SDK in a Next.js application. You can now proceed to build more complex functionalities into your decentralized application.

Last updated