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.
Prerequisites
Node.js and npm installed
Basic understanding of Next.js and React
A Bastion account for API key
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
Log in to the Bastion Dashboard.
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