Crossmint App

Overview

In today's web3 ecosystem, creating truly decentralized applications requires more than just smart contracts. You need decentralized storage, seamless user experiences, and simplified payment options. Unfortunately, more than 95% of all web3 dApps are deployed on centralized platforms like Vercel.

This guide will walk you through building a completely decentralized NFT minting app that leverages the power of Arweave for permanent storage and Crossmint for simplified NFT creation. You'll learn how to store NFT content permanently, create and mint NFTs, build a frontend with authentication and payment options, and deploy your application to Arweave.

By the end of this tutorial, you'll have created a fully functional dApp that allows users to:

  • Log into your app easily through Crossmint's Auth
  • Purchase semi-fungible tokens (SFTs) following the ERC-1155 standard
  • Pay for SFTs using Crossmint with crypto or credit card
  • Access your application through a human-readable ArNS domain

You'll be well versed in building fully decentralized apps with the Crossmint SDK, ArDrive SDK, and the AR.IO SDK.

Example Project

Here's a quick overview of what you'll learn:

  1. Storage Setup: You'll begin by storing an AI-generated image on Arweave using ArDrive.io, ensuring your NFT content is permanently preserved.

  2. Collection and Template Creation: You'll create an ERC-1155 collection and template on Crossmint where your semi-fungible tokens will be minted.

  3. SFT Minting: You'll use Crossmint's API to mint semi-fungible tokens from your template, following their straightforward API guide.

  4. Frontend Development: You'll clone the Zero-to-Arweave starter kit, which provides a solid foundation using Vite, React, and JavaScript along with the AR.IO SDK and ArDrive SDKs.

  5. Authentication Integration: You'll implement Crossmint's client-side authentication system, making it easy for users to interact with your application.

  6. Payment Integration: You'll add Crossmint's embedded checkout to enable users to purchase SFTs with both crypto and credit cards.

  7. Frontend Design Improvements: You'll update the frontend design to better showcase your NFTs and create a more intuitive user flow.

  8. Decentralized Deployment: You'll deploy your completed frontend to Arweave, ensuring your entire application stack is decentralized and permanently accessible.

  9. Domain Configuration: Finally, you'll configure your ArNS domain to point to your newly deployed application, providing users with a friendly URL to access your dApp.

Let's get into the code!

Step 1: Storage Setup

First, you'll need to store your NFT image on Arweave using ardrive.io. This step ensures that your NFT's visual content is permanently preserved on the decentralized Arweave network.

Generate an AI Image

Start by creating an AI-generated image that will become your NFT:

  1. Visit ChatGPT (https://chat.openai.com/) or another AI image generation tool

  2. Use a prompt to generate an interesting image for your NFT

  3. Download the generated image to your local machine

  4. Make sure to save it in a common format like PNG or JPG

Store the Image on ArDrive.io

Now that you have your image, store it permanently on Arweave:

  1. Visit ArDrive.io and log in to your account (or create one if you're new)

  2. Fund your ArDrive wallet if needed (this requires AR tokens)

  3. Create a new folder for your NFT project

  4. Drag and drop your AI-generated image into this folder

  5. Wait for the upload to complete and for the transaction to be processed

Retrieve the Arweave Transaction ID

Once your image is successfully uploaded:

  1. Click on the uploaded image in your ArDrive folder

  2. Look for the "Transaction ID" or "TX ID" in the file details

  3. Copy this Transaction ID - it looks something like Abc123XYZ... (a long alphanumeric string)

  4. Save this Transaction ID somewhere safe - you'll need it later when creating your NFT metadata

This Transaction ID is crucial as it's the permanent reference to your image on the Arweave network. When you create your SFT template in the next step, you'll include this ID to link the tokens to this permanently stored image.

Step 2: Collection and Template Creation

Next, you'll create an ERC-1155 collection and template using Crossmint's API. These will hold your semi-fungible tokens (SFTs).

Create a Crossmint Developer Account

  1. Visit the Crossmint Staging Console to create a developer account

  2. Sign in and accept the dialog to continue

  3. Note that Crossmint provides two environments:

    • Staging: For development and testing (what we'll use first)
    • Production: For your final, live application

Get a Server-Side API Key

  1. After logging in, navigate to the "Integrate" tab

  2. Click on "API Keys" at the top of the page

  3. In the "Server-side keys" section, click "Create new key"

  4. Select the following scopes under "Minting API":

    • collections.create - Required for creating a new collection
    • nfts.create - Required for minting NFTs
    • nfts.read - Needed to read NFT information
  5. Create and save this API key securely - you'll need it for our API calls

Create an ERC-1155 Collection

Let's create a collection for your semi-fungible tokens using Crossmint's API:

  1. Create a new file called createCollection.js in your project directory

  2. Add the following code:

const apiKey = "YOUR_API_KEY";
const env = "staging"; // Using staging environment for development

const url = `https://${env}.crossmint.com/api/2022-06-09/collections`;
const options = {
    method: "POST",
    headers: {
        "accept": "application/json",
        "content-type": "application/json",
        "x-api-key": apiKey,
    },
    body: JSON.stringify({
        chain: "ethereum-sepolia", // Using Ethereum testnet for development
        fungibility: "semi-fungible", // For ERC-1155 tokens
        metadata: {
            name: "lil dumdumz SFT Collection",
            imageUrl: "https://arweave.net/YOUR_ARWEAVE_TX_ID", // Optional collection image
            description: "A collection of semi-fungible tokens with images stored on Arweave"
        }
    }),
};

fetch(url, options)
    .then((res) => res.json())
    .then((json) => {
        console.log(json);
        console.log("Collection created! Collection ID:", json.id);
        console.log("Save this Collection ID for the next steps");
    })
    .catch((err) => console.error("Error:", err));
  1. Replace the placeholders:

    • YOUR_API_KEY with the API key you created in the previous step
    • YOUR_ARWEAVE_TX_ID with your collection image's Arweave Transaction ID (optional)
  2. Run the script with: node createCollection.js

  3. After a few seconds, you'll receive a response with the Collection ID - save this ID for the next steps

Create an SFT Template

Now, let's create a template within your collection from which you can mint multiple identical SFTs:

  1. Create a new file called createTemplate.js in your project directory

  2. Add the following code:

const apiKey = "YOUR_API_KEY";
const env = "staging"; // Using staging environment for development
const collectionId = "YOUR_COLLECTION_ID"; // From the previous step
const arweaveImageTxId = "YOUR_NFT_IMAGE_TX_ID"; // From Step 1

const url = `https://${env}.crossmint.com/api/2022-06-09/collections/${collectionId}/templates`;
const options = {
    method: "POST",
    headers: {
        "accept": "application/json",
        "content-type": "application/json",
        "x-api-key": apiKey,
    },
    body: JSON.stringify({
        onChain: {
            tokenId: "1" // You can assign any unique ID to this template
        },
        supply: {
            limit: 100 // Maximum number of tokens that can be minted from this template
        },
        metadata: {
            name: "lil dumdumz SFT",
            image: `https://arweave.net/${arweaveImageTxId}`, // Arweave gateway URL
            description: "Semi-fungible token with image permanently stored on Arweave",
            attributes: [
                {
                    trait_type: "Storage",
                    value: "Arweave"
                },
                {
                    trait_type: "Permanence",
                    value: "Forever"
                }
            ]
        }
    }),
};

fetch(url, options)
    .then((res) => res.json())
    .then((json) => {
        console.log(json);
        console.log("Template created! Template ID:", json.id);
        console.log("Save this Template ID for minting SFTs");
    })
    .catch((err) => console.error("Error:", err));
  1. Replace the placeholders:

    • YOUR_API_KEY with your API key
    • YOUR_COLLECTION_ID with the Collection ID from the previous step
    • YOUR_NFT_IMAGE_TX_ID with the Arweave Transaction ID of your NFT image from Step 1
  2. Run the script with: node createTemplate.js

  3. After a few seconds, you'll receive a response with the Template ID - save this ID for minting SFTs

Step 3: SFT Minting

Now that you have your collection and template set up, let's mint an SFT from your template.

Create a Minting Script

  1. Create a new file called mintSFT.js in your project directory

  2. Add the following code:

const apiKey = "YOUR_API_KEY";
const env = "staging"; // Using staging environment for development
const collectionId = "YOUR_COLLECTION_ID"; // From Step 2
const templateId = "YOUR_TEMPLATE_ID"; // From Step 2
const recipientEmail = "YOUR_EMAIL_ADDRESS"; // Replace with your email

const url = `https://${env}.crossmint.com/api/2022-06-09/collections/${collectionId}/sfts`;
const options = {
    method: "POST",
    headers: {
        "accept": "application/json",
        "content-type": "application/json",
        "x-api-key": apiKey,
    },
    body: JSON.stringify({
        templateId: templateId,
        recipient: `email:${recipientEmail}:ethereum-sepolia`, // Using email as recipient
        amount: 1 // Number of tokens to mint
    }),
};

fetch(url, options)
    .then((res) => res.json())
    .then((json) => {
        console.log(json);
        console.log("Minting initiated! Action ID:", json.actionId);
        console.log("Save this Action ID to check the minting status");
    })
    .catch((err) => console.error("Error:", err));
  1. Replace the placeholders:

    • YOUR_API_KEY with your API key
    • YOUR_COLLECTION_ID with the Collection ID from Step 2
    • YOUR_TEMPLATE_ID with the Template ID from Step 2
    • YOUR_EMAIL_ADDRESS with your email for testing
  2. Run the script with: node mintSFT.js

  3. After a few seconds, you'll receive a response with an Action ID - save this ID for checking the minting status

Check Minting Status

Since blockchain transactions take time to confirm, you need to check the status of your mint:

  1. Create a new file called checkMintStatus.js with the following code:
const apiKey = "YOUR_API_KEY";
const env = "staging";
const actionId = "YOUR_ACTION_ID"; // From the previous step

const url = `https://${env}.crossmint.com/api/2022-06-09/actions/${actionId}`;
const options = {
    method: "GET",
    headers: { "x-api-key": apiKey },
};

fetch(url, options)
    .then((response) => response.json())
    .then((response) => {
        console.log(response);
        console.log("Minting Status:", response.status);
    })
    .catch((err) => console.error(err));
  1. Replace the placeholders with your API key and the Action ID from the previous step

  2. Run the script with: node checkMintStatus.js

  3. Keep checking until the status field returns "success"

View Your Newly Minted SFT

Once the minting is successful, you can view your SFT by:

  1. Logging into your wallet from Crossmint's staging website

  2. Looking for your newly minted SFT with the Arweave-stored image

  3. Verify that all the metadata appears correctly, including the image from Arweave

Congratulations! You've now successfully created a collection, defined a template, and minted an SFT with its image permanently stored on Arweave. This combination provides true decentralization for your token's content.

In the next step, you'll set up your frontend application by cloning the Zero-to-Arweave starter kit.

Step 4: Frontend Development

Now that you have your image stored on Arweave and your NFT contract deployed with Crossmint, let's set up the frontend application. You'll use the Zero-to-Arweave Starter Kit, which provides a solid foundation for building decentralized applications on Arweave.

Clone the Starter Kit

  1. Open your terminal and clone the starter kit repository:
git clone https://github.com/ar-io/ZeroToArweave-StarterKit.git
cd ZeroToArweave-StarterKit

Install Dependencies

  1. Install the required dependencies using your preferred package manager:
# Using pnpm
pnpm install

# OR using yarn
yarn install

Configure Your Arweave Wallet

  1. Place your Arweave wallet file in the project root as wallet.json. This will be required for deploying the application later, but you'll need it now to test the app functionality.
Important

Never commit your wallet file to version control. The starter kit includes wallet.json in its .gitignore file by default.

Explore the Project Structure

  1. Take a moment to understand the project structure:
├── public/              # Static assets
├── scripts/             # Deployment and configuration scripts
├── src/
│   ├── components/      # Reusable UI components
│   ├── hooks/           # Custom React hooks
│   ├── pages/           # Application pages
│   ├── App.jsx          # Main application component
│   ├── main.jsx         # Application entry point
├── .env                 # Environment variables
├── index.html           # HTML entry point
├── package.json         # Project dependencies and scripts
├── vite.config.js       # Vite configuration

Customize the Application

  1. Let's customize the application for your NFT minting project. First, update the title and description in index.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Decentralized NFT Minting App</title>
    <meta name="description" content="Mint NFTs stored permanently on Arweave using Crossmint" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
  1. Update the homepage in src/pages/Home.jsx to include information about your NFT minting application:
import React from 'react';
import { ConnectButton } from '@arweave-wallet-kit/react';

const Home = () => {
  return (
    <div className="container mx-auto px-4 py-8">
      <h1 className="text-4xl font-bold mb-6">Decentralized NFT Minting</h1>
      
      <div className="bg-gray-100 p-6 rounded-lg mb-8">
        <h2 className="text-2xl font-semibold mb-4">About This Project</h2>
        <p className="mb-4">
          This is a fully decentralized NFT minting application that leverages:
        </p>
        <ul className="list-disc pl-6 mb-4">
          <li>Arweave for permanent image storage</li>
          <li>Crossmint for simplified NFT minting</li>
          <li>AR.IO for decentralized domain names</li>
        </ul>
        <p>
          Connect your wallet to get started with minting your own NFTs.
        </p>
      </div>
      
      <div className="text-center mb-8">
        <ConnectButton className="bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded" />
      </div>
    </div>
  );
};

export default Home;

Start the Development Server

  1. Run the development server to make sure everything is working properly:
pnpm run dev  # or yarn dev
  1. Open your browser to the URL shown in the terminal (typically http://localhost:5173) to see your application.

At this point, you should see your customized frontend with the Arweave wallet integration working. The application is still missing your Crossmint integration, which you'll add in the next steps.

The Zero-to-Arweave Starter Kit provides all the necessary SDKs and configurations to work with Arweave, including:

  • Arweave Wallet Kit for wallet connections

  • AR.IO SDK for domain name management

  • Turbo SDK for efficient data uploads

In the next step, you'll add Crossmint's client-side authentication to allow users to interact with your NFT minting functionality.

Step 5: Authentication Integration

Now you need to integrate Crossmint's client-side authentication into your app. This will allow users to log in and interact with your NFT minting functionality seamlessly. Let's implement Crossmint Auth in your Zero-to-Arweave starter kit.

Create and Configure a Crossmint Project

  1. If you haven't already, go to the Crossmint Staging Console and log in or create an account

Get a Client-Side API Key

  1. Navigate to the "Integrate" section in the left navigation bar

  2. Click on the "API Keys" tab

  3. In the "Client-side keys" section, click "Create new key"

  4. Add your development URL as an authorized origin:

    • For local development: http://localhost:5173 (Vite's default port)
  5. Select the following scopes:

    • users.create - Required for authentication functionality
    • users.read - Needed to read user information
  6. Enable "JWT Auth" by checking the box

  7. Create the key and save it for the next steps

Set Up Environment Variables

  1. Create a .env file in the root of your project (or modify the existing one) and add your Crossmint API key:
VITE_CROSSMINT_API_KEY="YOUR_CLIENT_SIDE_API_KEY"

Install the Crossmint SDK

  1. Install the Crossmint React SDK:
pnpm add @crossmint/client-sdk-react-ui

Create a Providers Component

  1. Create a new file at src/components/CrossmintProviders.jsx:
import { CrossmintProvider, CrossmintAuthProvider } from "@crossmint/client-sdk-react-ui";

export default function CrossmintProviders({ children }) {
  return (
    <CrossmintProvider apiKey={import.meta.env.VITE_CROSSMINT_API_KEY || ""}>
      <CrossmintAuthProvider
        loginMethods={["email", "google", "farcaster"]} // You can customize these methods
      >
        {children}
      </CrossmintAuthProvider>
    </CrossmintProvider>
  );
}

Update Main Application Entry Point

  1. Modify your src/main.jsx file to include the Crossmint providers:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { HashRouter } from 'react-router-dom'
import { ArweaveWalletKit } from '@arweave-wallet-kit/react'
import WanderStrategy from '@arweave-wallet-kit/wander-strategy'
import BrowserWalletStrategy from '@arweave-wallet-kit/browser-wallet-strategy'
import WebWalletStrategy from '@arweave-wallet-kit/webwallet-strategy'
import CrossmintProviders from './components/CrossmintProviders'
import './index.css'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <HashRouter>
      <ArweaveWalletKit
        config={{
          permissions: [
            'ACCESS_ADDRESS',
            'ACCESS_PUBLIC_KEY',
            'SIGN_TRANSACTION',
            'DISPATCH',
          ],
          ensurePermissions: true,
          strategies: [
            new WanderStrategy(),
            new BrowserWalletStrategy(),
            new WebWalletStrategy(),
          ],
        }}
      >
        <CrossmintProviders>
          <App />
        </CrossmintProviders>
      </ArweaveWalletKit>
    </HashRouter>
  </StrictMode>,
)

Create an Authentication Component

  1. Create a new component at src/components/AuthButton.jsx:
import { useAuth } from "@crossmint/client-sdk-react-ui";

function AuthButton() {
  const { login, logout, user } = useAuth();

  return (
    <div className="flex flex-col items-center gap-4">
      {user == null ? (
        <button
          type="button"
          onClick={login}
          className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
        >
          Sign in with Crossmint
        </button>
      ) : (
        <div className="flex flex-col items-center gap-4">
          <div className="bg-white p-4 rounded-lg shadow-md">
            <h3 className="font-bold text-lg mb-2">User Info</h3>
            <p><span className="font-medium">User ID:</span> {user?.userId}</p>
            <p><span className="font-medium">Email:</span> {user?.email || "Not available"}</p>
            {user?.google && (
              <p><span className="font-medium">Google:</span> {user.google.displayName}</p>
            )}
            {user?.farcaster && (
              <p><span className="font-medium">Farcaster:</span> {user.farcaster.username}</p>
            )}
          </div>
          
          <button
            type="button"
            onClick={logout}
            className="bg-gray-800 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded"
          >
            Sign Out
          </button>
        </div>
      )}
    </div>
  );
}

export default AuthButton;

Simplify the NavBar Component

  1. We'll create a simplified NavBar component that only includes the AuthButton:
import AuthButton from './AuthButton';

function NavBar() {
  return (
    <nav className="bg-white shadow-lg">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="flex justify-between h-16 items-center">
          {/* Logo/Brand */}
          <div className="flex-shrink-0">
            <a href="/" className="text-xl font-bold text-gray-800 hover:text-gray-600 transition-colors">
              lil dumdumz NFT
            </a>
          </div>

          {/* Center Navigation - Empty for now */}
          <div className="flex-1 flex justify-center items-center">
            {/* Can add navigation links here in the future */}
          </div>

          {/* Authentication Button - Right Aligned */}
          <div className="flex-shrink-0 ml-4">
            <AuthButton />
          </div>
        </div>
      </div>
    </nav>
  );
}

export default NavBar;

Create a Protected Route Component

  1. Create a component to protect routes that require authentication at src/components/ProtectedRoute.jsx:
import { useAuth } from "@crossmint/client-sdk-react-ui";
import { Navigate } from "react-router-dom";

const ProtectedRoute = ({ children }) => {
  const { user, isLoading } = useAuth();

  if (isLoading) {
    return <div className="text-center p-8">Loading authentication state...</div>;
  }

  if (!user) {
    return <Navigate to="/" />;
  }

  return children;
};

export default ProtectedRoute;

Test the Authentication Flow

  1. Start your development server:
pnpm run dev
  1. Visit your application in the browser and test these features:

    • Sign in button should open the Crossmint authentication modal

    • After signing in, you should see your user information displayed

    • Sign out button should work correctly

Customization Notes

In our implementation, we made the following changes to improve the user experience:

  1. Simplified the NavBar - We removed the Arweave wallet connection and ARIO SDK functionality to focus solely on Crossmint authentication, creating a cleaner interface.

  2. Streamlined User Interface - The app now shows a single "Sign in with Crossmint" button in the navbar, which provides a more intuitive authentication flow.

  3. Removed Redundant Components - We eliminated unused state variables and effects from the NavBar component, making the code more maintainable.

  4. Enhanced Brand Identity - Changed all references to "lil dumdumz NFT" to strengthen the brand presence in the application.

With Crossmint's authentication now integrated, your users can easily sign up and log in to your decentralized NFT minting application. In the next step, you'll add the Crossmint payment button to enable users to mint NFTs directly from your application.

Step 6: Payment Integration (Crypto Payments)

For your fully decentralized NFT minting application, you've implemented a client-side approach for payment integration using Crossmint's headless API for crypto payments. This allows users to purchase NFTs directly from your application using cryptocurrency, maintaining the decentralized nature of your platform.

Environment Variables Setup

You've configured your application with the necessary environment variables:

VITE_CROSSMINT_API_KEY="your_staging_client_side_api_key"
VITE_CROSSMINT_COLLECTION_ID="your_staging_collection_id"

Both the API key and collection ID are from the staging environment, ensuring compatibility between the two.

Purchase Page Implementation

You've created a Purchase.jsx component that implements the complete crypto payment flow:

  1. Wallet Connection: Allows users to connect their MetaMask wallet to the application
  2. Order Creation: Creates an order with Crossmint's API using the connected wallet address
  3. Recipient Assignment: Assigns the authenticated user as the recipient of the NFT
  4. Payment Processing: Prompts the user to sign a transaction in their wallet
  5. Status Tracking: Polls the order status until completion

Here's an overview of how your Purchase component is structured:

// Purchase.jsx
import React, { useState, useEffect } from 'react';
import { useAuth } from "@crossmint/client-sdk-react-ui";

const Purchase = () => {
  const { user } = useAuth();
  const apiKey = import.meta.env.VITE_CROSSMINT_API_KEY;
  const collectionId = import.meta.env.VITE_CROSSMINT_COLLECTION_ID;
  
  // State variables for the payment flow
  const [payerAddress, setPayerAddress] = useState('');
  const [orderId, setOrderId] = useState(null);
  const [orderStatus, setOrderStatus] = useState('');
  const [serializedTransaction, setSerializedTransaction] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  // Functions for wallet connection, order creation, order updating,
  // transaction sending, and status polling...
  
  return (
    <div className="container mx-auto px-4 py-8">
      {/* Component UI with conditional rendering based on state */}
    </div>
  );
};

export default Purchase;

Crypto Payment Flow

The crypto payment flow in your application follows these steps:

  1. Connect Wallet: User connects their MetaMask wallet to the application

    const connectWallet = async () => {
      const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
      setPayerAddress(accounts[0]);
    };
    
  2. Create Order: Application creates an order with Crossmint's API

    const createOrder = async () => {
      const response = await fetch('https://staging.crossmint.com/api/2022-06-09/orders', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': apiKey
        },
        body: JSON.stringify({
          payment: {
            method: 'base-sepolia',
            currency: 'eth',
            payerAddress: payerAddress
          },
          lineItems: {
            collectionLocator: `crossmint:${collectionId}`,
            callData: {
              totalPrice: '0.01'
            }
          }
        })
      });
      // Handle response...
    };
    
  3. Update Order with Recipient: Application assigns the NFT to the authenticated user

    const updateOrderWithRecipient = async (id) => {
      const response = await fetch(`https://staging.crossmint.com/api/2022-06-09/orders/${id}`, {
        method: 'PATCH',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': apiKey
        },
        body: JSON.stringify({
          recipient: {
            email: user.email
          }
        })
      });
      // Handle response and set serializedTransaction...
    };
    
  4. Send Transaction: User signs and sends the transaction from their wallet

    const sendTransaction = async () => {
      await window.ethereum.request({
        method: 'eth_sendTransaction',
        params: [JSON.parse(serializedTransaction)]
      });
      // Start polling for status...
    };
    
  5. Poll for Status: Application checks the order status until completion

    const pollOrderStatus = async () => {
      const response = await fetch(`https://staging.crossmint.com/api/2022-06-09/orders/${orderId}`, {
        headers: {
          'x-api-key': apiKey
        }
      });
      // Update status and continue polling if needed...
    };
    

User Interface Elements

Your Purchase page includes several key UI elements:

  1. NFT Display: Shows the NFT image and details
  2. Connect Wallet Button: Allows users to connect their cryptocurrency wallet
  3. Create Order Button: Initiates the purchase process
  4. Pay with Crypto Button: Appears when ready for payment
  5. Status Messages: Keeps users informed about the current state of their purchase
  6. Success/Failure Messages: Provides feedback on the outcome of the purchase

Authentication Integration

Your payment flow is integrated with Crossmint's authentication system:

  • Only authenticated users can initiate the purchase process
  • The user's email from their Crossmint account is used as the recipient for the NFT
  • Protected routes ensure only authenticated users can access the Purchase page

App Routes Update

You've updated the application routes to include the Purchase page:

// App.jsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Purchase from './pages/Purchase';
import ProtectedRoute from './components/ProtectedRoute';
import NavBar from './components/NavBar';

function App() {
  return (
    <>
      <NavBar />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route 
          path="/purchase" 
          element={
            <ProtectedRoute>
              <Purchase />
            </ProtectedRoute>
          } 
        />
      </Routes>
    </>
  );
}

export default App;

NavBar Update

You've also updated the NavBar component to include a link to the Purchase page:

import { Link } from 'react-router-dom';
import AuthButton from './AuthButton';
import { useAuth } from "@crossmint/client-sdk-react-ui";

function NavBar() {
  const { user } = useAuth();
  
  return (
    <nav className="bg-white shadow-lg">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="flex justify-between h-16 items-center">
          {/* Logo/Brand */}
          <div className="flex-shrink-0">
            <Link to="/" className="text-xl font-bold text-gray-800 hover:text-gray-600 transition-colors">
              lil dumdumz NFT
            </Link>
          </div>

          {/* Center Navigation */}
          <div className="flex-1 flex justify-center items-center">
            {user && (
              <Link 
                to="/purchase" 
                className="mx-4 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
              >
                Purchase NFT
              </Link>
            )}
          </div>

          {/* Authentication Button */}
          <div className="flex-shrink-0 ml-4">
            <AuthButton />
          </div>
        </div>
      </div>
    </nav>
  );
}

export default NavBar;

Testing the Crypto Payment Flow

To test the complete purchase flow:

  1. Start the development server with pnpm run dev
  2. Sign in with Crossmint using the AuthButton
  3. Navigate to the Purchase page
  4. Connect your MetaMask wallet to the application
  5. Create an order by clicking the Create Order button
  6. When prompted, sign the transaction in your wallet
  7. Monitor the order status until completion
  8. Verify that the NFT appears in your Crossmint wallet

Benefits of the Crypto Payment Approach

This crypto payment implementation offers several advantages:

  1. Fully Decentralized: The entire payment process happens client-side, aligning with your goal of a decentralized application
  2. Native Blockchain Experience: Users interact directly with their wallets for a true web3 experience
  3. No Server-Side Requirements: All API calls are made from the client, making the app compatible with Arweave deployment
  4. Transparent Process: Users can see and verify each step of the transaction process
  5. Cross-Chain Compatibility: The same approach can be used to accept payments on various blockchains

By implementing this payment flow, you've created a seamless way for users to purchase NFTs using cryptocurrency while maintaining the decentralized nature of your application. This sets the stage for the next step: deploying your complete application to Arweave.

Step 7: Frontend Design Improvements

After implementing the core functionality of your application, it's important to enhance the user interface to create a more engaging and professional experience. A well-designed UI not only improves usability but also increases user trust in your NFT platform. Let's update your frontend design to better showcase your NFTs and create a more intuitive user flow.

Redesigning the NavBar Component

First, let's enhance your NavBar with a modern design and responsive functionality:

import { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { useAuth } from "@crossmint/client-sdk-react-ui";
import AuthButton from './AuthButton';

function NavBar() {
  const { user } = useAuth();
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const location = useLocation();

  const isActive = (path) => {
    return location.pathname === path;
  };

  return (
    <nav className="bg-white shadow-lg sticky top-0 z-50">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="flex justify-between h-16 items-center">
          {/* Logo/Brand with gradient text effect */}
          <div className="flex-shrink-0">
            <Link to="/" className="flex items-center">
              <span className="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-indigo-600 to-purple-600">
                lil dumdumz NFT
              </span>
            </Link>
          </div>

          {/* Desktop Navigation with active state indicators */}
          <div className="hidden md:flex items-center space-x-6">
            <Link 
              to="/" 
              className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
                isActive('/') 
                  ? 'text-indigo-600 bg-indigo-50' 
                  : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
              }`}
            >
              Home
            </Link>
            
            {user && (
              <>
                <Link 
                  to="/purchase" 
                  className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
                    isActive('/purchase') 
                      ? 'text-indigo-600 bg-indigo-50' 
                      : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
                  }`}
                >
                  Purchase NFT
                </Link>
                <Link 
                  to="/dashboard" 
                  className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
                    isActive('/dashboard') 
                      ? 'text-indigo-600 bg-indigo-50' 
                      : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
                  }`}
                >
                  Dashboard
                </Link>
              </>
            )}
          </div>

          {/* Authentication Button - Desktop */}
          <div className="hidden md:block">
            <AuthButton />
          </div>

          {/* Mobile menu button with animation */}
          <div className="md:hidden flex items-center">
            <button 
              onClick={() => setIsMenuOpen(!isMenuOpen)}
              className="inline-flex items-center justify-center p-2 rounded-md text-gray-700 hover:text-indigo-600 hover:bg-gray-50 focus:outline-none"
              aria-expanded="false"
            >
              <span className="sr-only">Open main menu</span>
              {/* Icon when menu is closed */}
              <svg
                className={`${isMenuOpen ? 'hidden' : 'block'} h-6 w-6`}
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                aria-hidden="true"
              >
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" />
              </svg>
              {/* Icon when menu is open */}
              <svg
                className={`${isMenuOpen ? 'block' : 'hidden'} h-6 w-6`}
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                aria-hidden="true"
              >
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
              </svg>
            </button>
          </div>
        </div>
      </div>

      {/* Mobile menu, show/hide based on menu state */}
      <div className={`${isMenuOpen ? 'block' : 'hidden'} md:hidden`}>
        <div className="px-2 pt-2 pb-3 space-y-1 sm:px-3 border-t border-gray-200">
          <Link
            to="/"
            className={`block px-3 py-2 rounded-md text-base font-medium ${
              isActive('/') 
                ? 'text-indigo-600 bg-indigo-50' 
                : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
            }`}
            onClick={() => setIsMenuOpen(false)}
          >
            Home
          </Link>
          
          {user && (
            <>
              <Link
                to="/purchase"
                className={`block px-3 py-2 rounded-md text-base font-medium ${
                  isActive('/purchase') 
                    ? 'text-indigo-600 bg-indigo-50' 
                    : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
                }`}
                onClick={() => setIsMenuOpen(false)}
              >
                Purchase NFT
              </Link>
              <Link
                to="/dashboard"
                className={`block px-3 py-2 rounded-md text-base font-medium ${
                  isActive('/dashboard') 
                    ? 'text-indigo-600 bg-indigo-50' 
                    : 'text-gray-700 hover:text-indigo-600 hover:bg-gray-50'
                }`}
                onClick={() => setIsMenuOpen(false)}
              >
                Dashboard
              </Link>
            </>
          )}
        </div>
        
        {/* Mobile Authentication Button */}
        <div className="pt-4 pb-3 border-t border-gray-200">
          <div className="px-2">
            <AuthButton />
          </div>
        </div>
      </div>
    </nav>
  );
}

export default NavBar;

This updated NavBar includes:

  1. Modern Design Elements:

    • Gradient text for the brand name
    • Subtle hover and active state animations
    • Clean, consistent spacing
    • Sticky positioning so it remains visible while scrolling
  2. Responsive Features:

    • Collapsible mobile menu with toggle button
    • Different layouts for mobile and desktop
    • Automatic menu closing when a link is clicked
  3. User Experience Improvements:

    • Visual feedback for the current active page
    • Conditional navigation links based on authentication status
    • Accessible design with proper ARIA attributes
  4. Enhanced Brand Identity:

    • Consistent color scheme, typography, and styling elements
    • Strengthened "lil dumdumz NFT" brand presence
  5. Improved Conversion Rates:

    • Strategic placement of call-to-action buttons
    • Clear value propositions for the platform's benefits

Enhancing the App Layout

Next, you'll update your App.jsx to use a more structured layout that provides consistency across all pages:

import NavBar from './components/NavBar';
import { useConnection } from '@arweave-wallet-kit/react';
import { Routes, Route, Navigate } from 'react-router-dom';
import './App.css';
import Home from './components/Home';
import Purchase from './pages/Purchase';
import ProtectedRoute from './components/ProtectedRoute';

function App() {
  const { connected } = useConnection();

  return (
    <div className="flex flex-col min-h-screen bg-gradient-to-b from-gray-50 to-gray-100">
      <NavBar />
      
      <main className="flex-grow">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/purchase" element={
            <ProtectedRoute>
              <Purchase />
            </ProtectedRoute>
          } />
        </Routes>
      </main>
    </div>
  );
}

export default App;

The new App.jsx layout includes:

  • A full-height flexible layout with a subtle gradient background
  • Consistent page structure with appropriate margins and padding
  • A placeholder dashboard with skeleton loading states for future NFT displays
  • Proper routing with protected routes for authenticated content

Creating an Engaging Home Page

A good landing page is crucial for NFT platforms. You've redesigned your Home component to create a more engaging and informative experience:

import React from 'react';
import { Link } from 'react-router-dom';
import { useAuth } from "@crossmint/client-sdk-react-ui";

const Home = () => {
  const { user, login } = useAuth();
  const arweaveImageUrl = "https://btruuwgkero6dqsk6y2w72kgbtfbncafhdch3bepa33cdpxxdhfa.arweave.net/DONKWMokXeHCSvY1b-lGDMoWiAU4xH2Ejwb2Ib73Gco";

  return (
    <>
      {/* Hero Section */}
      <section className="bg-gradient-to-r from-indigo-600 to-purple-600 text-white">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 md:py-28">
          <div className="grid md:grid-cols-2 gap-12 items-center">
            <div className="text-center md:text-left">
              <h1 className="text-4xl md:text-5xl font-bold mb-6 leading-tight">
                Collect Unique Digital Art from lil dumdumz
              </h1>
              <p className="text-xl mb-8 text-indigo-100">
                Fully decentralized NFTs with permanent storage on Arweave. Own a piece of digital history that lasts forever.
              </p>
              <div className="flex flex-col sm:flex-row justify-center md:justify-start gap-4">
                {user ? (
                  <Link 
                    to="/purchase" 
                    className="px-8 py-3 bg-white text-indigo-600 rounded-full font-bold text-lg shadow-lg hover:bg-indigo-50 transition duration-300"
                  >
                    Purchase NFT
                  </Link>
                ) : (
                  <button
                    onClick={login}
                    className="px-8 py-3 bg-white text-indigo-600 rounded-full font-bold text-lg shadow-lg hover:bg-indigo-50 transition duration-300"
                  >
                    Connect Wallet
                  </button>
                )}
                <a 
                  href="#learn-more" 
                  className="px-8 py-3 bg-transparent border-2 border-white rounded-full font-bold text-lg hover:bg-white hover:bg-opacity-10 transition duration-300"
                >
                  Learn More
                </a>
              </div>
            </div>
            <div className="relative">
              <div className="relative z-10 overflow-hidden rounded-2xl shadow-2xl transform rotate-2 hover:rotate-0 transition-transform duration-500">
                <img 
                  src={arweaveImageUrl} 
                  alt="Featured NFT" 
                  className="w-full h-auto"
                />
                <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-6">
                  <p className="text-white text-xl font-semibold">lil dumdumz #1</p>
                  <div className="flex justify-between items-center mt-2">
                    <span className="text-indigo-200">Price: 0.01 ETH</span>
                    <span className="bg-indigo-500 text-white px-3 py-1 rounded-full text-sm">Limited Edition</span>
                  </div>
                </div>
              </div>
              <div className="absolute -bottom-5 -right-5 h-48 w-48 bg-yellow-400 rounded-full opacity-70 blur-3xl -z-10"></div>
              <div className="absolute -top-5 -left-5 h-36 w-36 bg-purple-500 rounded-full opacity-70 blur-3xl -z-10"></div>
            </div>
          </div>
        </div>
      </section>

      {/* Features Section */}
      <section id="learn-more" className="py-20 bg-white">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <h2 className="text-3xl font-bold text-center mb-16 text-gray-800">
            A Truly <span className="text-indigo-600">Decentralized</span> NFT Platform
          </h2>
          
          <div className="grid md:grid-cols-3 gap-12">
            <div className="bg-gray-50 rounded-xl p-8 shadow-md transform hover:scale-105 transition duration-300">
              <div className="h-14 w-14 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mb-6">
                <svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
                </svg>
              </div>
              <h3 className="text-xl font-semibold mb-3 text-gray-800">Permanent Storage</h3>
              <p className="text-gray-600">
                Your NFT images are stored on Arweave, ensuring they'll be accessible forever. No more broken NFTs due to centralized servers going offline.
              </p>
            </div>
            
            <div className="bg-gray-50 rounded-xl p-8 shadow-md transform hover:scale-105 transition duration-300">
              <div className="h-14 w-14 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mb-6">
                <svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
                </svg>
              </div>
              <h3 className="text-xl font-semibold mb-3 text-gray-800">Simplified Purchasing</h3>
              <p className="text-gray-600">
                Crossmint integration allows for easy NFT purchasing with cryptocurrency, making blockchain technology accessible to everyone.
              </p>
            </div>
            
            <div className="bg-gray-50 rounded-xl p-8 shadow-md transform hover:scale-105 transition duration-300">
              <div className="h-14 w-14 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mb-6">
                <svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
                </svg>
              </div>
              <h3 className="text-xl font-semibold mb-3 text-gray-800">Decentralized Domain</h3>
              <p className="text-gray-600">
                Your app is hosted on the AR.IO network, ensuring it will remain accessible indefinitely with a human-readable domain name.
              </p>
            </div>
          </div>
        </div>
      </section>

      {/* NFT Preview Section */}
      <section className="py-20 bg-gray-50">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="text-center mb-16">
            <h2 className="text-3xl font-bold text-gray-800 mb-4">Featured NFT</h2>
            <p className="text-lg text-gray-600 max-w-3xl mx-auto">
              A limited edition artwork with permanent storage on the Arweave network, and verification on the Base Sepolia blockchain.
            </p>
          </div>
          
          <div className="bg-white rounded-2xl shadow-xl overflow-hidden max-w-4xl mx-auto">
            <div className="md:flex">
              <div className="md:w-1/2">
                <img 
                  src={arweaveImageUrl} 
                  alt="Featured NFT" 
                  className="w-full h-full object-cover"
                />
              </div>
              <div className="md:w-1/2 p-8">
                <h3 className="text-2xl font-bold text-gray-800 mb-4">lil dumdumz NFT #1</h3>
                <div className="flex items-center mb-6">
                  <span className="bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm mr-3">Available</span>
                  <span className="text-gray-500 text-sm">Limited Edition of 100</span>
                </div>
                <p className="text-gray-600 mb-6">
                  This unique NFT features stunning artwork permanently stored on the Arweave network, 
                  ensuring its availability for generations to come. Own a piece of digital history that can't be altered or deleted.
                </p>
                <div className="border-t border-gray-200 pt-6 mb-6">
                  <div className="flex justify-between mb-2">
                    <span className="text-gray-500">Storage</span>
                    <span className="font-medium">Arweave</span>
                  </div>
                  <div className="flex justify-between mb-2">
                    <span className="text-gray-500">Blockchain</span>
                    <span className="font-medium">Base Sepolia</span>
                  </div>
                  <div className="flex justify-between mb-2">
                    <span className="text-gray-500">Price</span>
                    <span className="font-medium">0.01 ETH</span>
                  </div>
                </div>
                {user ? (
                  <Link 
                    to="/purchase" 
                    className="block w-full py-3 px-4 bg-indigo-600 text-white text-center font-medium rounded-lg hover:bg-indigo-700 transition duration-300"
                  >
                    Purchase This NFT
                  </Link>
                ) : (
                  <button
                    onClick={login}
                    className="block w-full py-3 px-4 bg-indigo-600 text-white text-center font-medium rounded-lg hover:bg-indigo-700 transition duration-300"
                  >
                    Connect Wallet to Purchase
                  </button>
                )}
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* CTA Section */}
      <section className="bg-indigo-600 text-white py-16 pb-24">
        <div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
          <h2 className="text-3xl font-bold mb-6">Ready to own your piece of digital history?</h2>
          <p className="text-xl text-indigo-100 mb-8 max-w-3xl mx-auto">
            Join the movement for truly permanent digital ownership with our decentralized NFT platform.
          </p>
          {user ? (
            <Link 
              to="/purchase" 
              className="inline-block px-8 py-4 bg-white text-indigo-600 rounded-full font-bold text-lg shadow-lg hover:bg-indigo-50 transition duration-300"
            >
              Purchase Your NFT Now
            </Link>
          ) : (
            <button
              onClick={login}
              className="inline-block px-8 py-4 bg-white text-indigo-600 rounded-full font-bold text-lg shadow-lg hover:bg-indigo-50 transition duration-300"
            >
              Connect Wallet to Get Started
            </button>
          )}
        </div>
      </section>
    </>
  );
};

export default Home;

This enhanced Home page includes several key elements:

  1. Engaging Hero Section:

    • A bold color gradient background with a two-column layout
    • Prominent headline and subheading that clearly communicates the value proposition
    • Featured NFT display with hover effects and overlay information
    • Call-to-action buttons that adapt based on user authentication status
  2. Features Explanation:

    • Three-column layout highlighting the key benefits of the platform
    • Custom icons with consistent styling
    • Interactive hover effects to increase engagement
    • Clear, concise descriptions of the advantages of using your platform
  3. NFT Showcase Section:

    • Detailed card displaying the NFT with its specifications
    • Responsive design that adapts to different screen sizes
    • Clear visual hierarchy with appropriate spacing
    • Contextual call-to-action based on authentication state
  4. Compelling Call-to-Action Section:

    • Bold color background to draw attention
    • Clear, benefit-focused headline
    • Prominent action button to drive conversions

Design Enhancement Benefits

These frontend improvements offer several advantages for your NFT platform:

  1. Increased User Engagement: The visually appealing design with interactive elements keeps users interested and encourages exploration.

  2. Better User Experience: The responsive design ensures a consistent experience across all devices, while the intuitive navigation makes the platform easy to use.

  3. Enhanced Brand Identity: The consistent color scheme, typography, and styling elements strengthen your "lil dumdumz NFT" brand identity.

  4. Improved Conversion Rates: Strategic placement of call-to-action buttons and clear value propositions help guide users toward purchasing NFTs.

  5. Accessibility Improvements: Proper contrast ratios, ARIA attributes, and semantic HTML make the platform more accessible to all users.

By implementing these design improvements, you've transformed your functional NFT platform into a visually appealing and user-friendly experience that better showcases your NFTs and encourages user interaction.

Step 8: Decentralized Deployment

Now that you have built your complete NFT minting application with Arweave storage and Crossmint integration, let's deploy it to the Arweave network. This will make your entire application permanently available and truly decentralized.

Prepare for Deployment

Before deploying, make sure you have:

  1. Your Arweave wallet file (wallet.json) in the project root

  2. Sufficient AR tokens in your wallet for the deployment transaction

  3. Turbo credits for fast uploads (available from turbo-topup.com)

Build the Production Version

  1. Build your application for production:
pnpm run build  # or yarn build

This will create optimized production files in the dist directory.

Deploy to Arweave

  1. The starter kit comes with a pre-configured deployment script. Run it to deploy your application:
pnpm run deploy  # or yarn deploy

This script will:

  • Take your built application from the dist directory

  • Upload all assets to Arweave using Turbo for faster deployment

  • Generate a manifest file that binds all your application files together

  • Provide you with a deployment URL in the format: https://arweave.net/{manifestId}

  1. Once the deployment completes, you'll see output similar to:
✅ Deployment successful!
📝 Manifest ID: YOUR_MANIFEST_ID
🔗 Your application is now available at: https://arweave.net/YOUR_MANIFEST_ID
  1. Important: Save this manifest ID as you'll need it for the next step.

Test Your Deployed Application

  1. Visit the provided URL (https://arweave.net/YOUR_MANIFEST_ID) to verify your application is working correctly.

  2. Test all functionality:

    • Arweave wallet connection

    • Crossmint authentication

    • NFT minting with the payment button

Since your application is now deployed to Arweave, it will remain accessible at this URL forever! Unlike traditional web hosting, there are no recurring fees or servers to maintain.

Benefits of Arweave Deployment

By deploying to Arweave, your NFT minting application gains several advantages:

  • Permanence: The application is stored permanently on the blockchain

  • Censorship resistance: No central authority can remove your application

  • No server maintenance: No need to manage servers or renew domains

  • True decentralization: Both the app's data (NFT images) and the application itself are decentralized

In the next and final step, you'll connect your deployed application to a human-readable domain name, making it easier for users to access.

Step 9: Domain Configuration

Now that your application is deployed to Arweave, the final step is to connect it to a human-readable domain name using the Arweave Name System (ArNS). This will make your dApp easily accessible with a memorable URL.

Prerequisites

Before configuring your domain, ensure you have:

  1. Successfully deployed your application to Arweave (from Step 8)

  2. The manifest ID from your deployment

  3. An ARNS name (purchased from arns.app)

  4. $ARIO tokens for transaction fees

Purchase an ARNS Name (if needed)

  1. If you don't already have an ARNS name:

    • Visit arns.app

    • Connect your Arweave wallet

    • Search for an available name

    • Purchase it with $ARIO tokens

Get Your Process ID

  1. To update your ARNS name:

    • Visit arns.app

    • Connect your Arweave wallet

    • Click "Manage Assets" in the top-right

    • Find your ARNS name and click on the settings icon

    • Copy the Process ID displayed in the management interface

Update the Base Record Configuration

  1. Open the /scripts/setBaseArns.js file in your project

  2. Update the processId in the configuration:

const ant = ANT.init({
    signer: new ArweaveSigner(jwk),
    processId: 'YOUR_PROCESS_ID_HERE'  // Replace with your Process ID
});
  1. Update the dataLink value with your deployment's manifest ID:
const result = await ant.setRecord({
    name: '@',
    ttlSeconds: 900,  // 15 minutes
    dataLink: 'YOUR_MANIFEST_ID'  // Replace with the manifest ID from Step 8
});

Set the Base Record

  1. Run the command to update your ARNS name with your application's manifest ID:
pnpm run set-base  # or yarn set-base
  1. The script will connect to AR.IO, submit the transaction, and update your name to point to your application. When successful, you'll see output similar to:
✅ Base record update successful!
🔗 Your application is now available at: https://YOUR-NAME.ar.io

Optional: Configure Undernames

  1. If you want to create subdomains for different parts of your application, you can set up undernames:

    • Open /scripts/setUndername.js

    • Update the processId with your Process ID

    • Configure the undername and data link

    • Run:

pnpm run set-undername  # or yarn set-undername

Verify Your Domain Configuration

  1. To verify all records associated with your ARNS name:

    • Open /scripts/getRecords.js

    • Update the processId with your Process ID

    • Run:

pnpm run records  # or yarn records
  1. This will display all the records for your ARNS name, including the base record that should now point to your application.

Access Your Application

  1. Your application is now accessible at:

    • https://YOUR-NAME.ar.io
  2. Share this user-friendly URL with your users - they can now access your fully decentralized NFT minting application using a memorable domain name.

Important Notes

  • ARNS name record updates may take a few minutes to propagate through the network

  • The default TTL (Time-to-Live) for name records is 15 minutes

  • If users experience issues accessing your domain, they can always use the direct Arweave URL: https://arweave.net/YOUR_MANIFEST_ID

Congratulations! 🎉 You've successfully built and deployed a fully decentralized NFT minting application that:

  1. Stores NFT images permanently on Arweave

  2. Mints NFTs on Ethereum using Crossmint

  3. Provides seamless authentication for users

  4. Offers multiple payment options for NFT purchases

  5. Is deployed in a truly decentralized manner on Arweave

  6. Is accessible via a human-readable domain name

Your application represents the future of Web3: decentralized storage, simplified user experiences, and permanent availability. Users can now mint NFTs with confidence, knowing that their digital assets will truly last forever on the permaweb supported by the permanent cloud solution, AR.IO.

Conclusion

Congratulations! You've successfully built an end-to-end decentralized NFT minting application that combines the permanent storage capabilities of Arweave with the user-friendly minting experience of Crossmint. This powerful combination creates a truly decentralized application that overcomes many of the traditional barriers to NFT adoption.

What You've Accomplished

In this tutorial, you've:

  1. Stored Content Permanently - Used ArDrive.io to store your NFT images on Arweave, ensuring they'll remain accessible forever

  2. Simplified NFT Creation - Integrated Crossmint's SDK to mint NFTs without requiring users to understand complex blockchain interactions

  3. Built a User-Friendly Frontend - Created a React application with wallet connection and authentication

  4. Added Payment Options - Implemented Crossmint's payment button to allow purchases with credit cards and cryptocurrencies

  5. Deployed Decentrally - Published your entire application to Arweave, ensuring it will remain available indefinitely

  6. Created a Memorable Address - Connected your application to a human-readable domain name

The Power of This Approach

This architecture solves several key problems in the NFT space:

  • True Permanence: Unlike NFTs that reference assets on centralized servers, your NFT images are stored permanently on Arweave

  • Accessibility: By offering credit card payments, you've made NFTs accessible to mainstream users

  • Complete Decentralization: Both your application and your assets are stored on decentralized networks

  • User-Friendly Experience: The combination of Arweave and Crossmint creates a seamless experience for both creators and collectors

Next Steps

To continue building on this foundation, consider:

  • Adding a gallery feature to display owned NFTs

  • Implementing NFT rarity traits and metadata

  • Creating a multi-creator marketplace

  • Adding social features like comments or likes

  • Building analytics to track sales and engagement

Resources

For more information on the technologies you've used:

By combining these powerful tools, you've built an application that represents the best of what Web3 has to offer: true ownership, permanence, permissionlessness, and accessibility. Your users can now mint NFTs with confidence, knowing that their digital assets will truly last forever on the permaweb supported by the permanent cloud solution, AR.IO.