DEV Community

Cover image for The Overview and walkthrough of Solana Dapp
Shivam Soni
Shivam Soni

Posted on

The Overview and walkthrough of Solana Dapp

Full stake dev guide

Solana - Dapp architecture

Tech stake-:

Nextjs, Anchor, Rust, and Phantom, solana tool suite, Solana web3.js

Overview

Building an NFT Minting and Transfer DApp on Solana with Next.js, Anchor, and Rust

Welcome In this guide, we'll walk you through building a dApp (decentralized application) on the Solana blockchain for minting and transferring non-fungible tokens (NFTs). We'll utilize the following technologies:

  • Solana: The high-performance blockchain platform
  • Next.js: A popular JavaScript framework for building fast and efficient React applications
  • Anchor: A framework that simplifies smart contract development on Solana using Rust
  • Rust: A powerful and memory-safe programming language used for Solana smart contracts
  • Phantom: A popular Solana wallet for interacting with your dApp
  • Solana Tool Suite: A collection of command-line tools for interacting with the Solana network
  • Solana web3.js: A JavaScript library for interacting with the Solana blockchain from the front-end

What We'll Build:

Throughout this guide, we'll create a basic dApp that allows users to:

  • Mint their own unique NFTs: Users will be able to mint NFT.
  • Transfer NFTs to other users: Users will be able to securely transfer ownership of their NFTs to other Solana wallet addresses.

Ready to embark on this exciting journey into the world of Solana NFT development? Let's dive in!

The Dapp-guide code-repo available here

https://github.com/shivamSspirit/spl-tokens

Solana Dapps

Solana DApps: What Makes Them Special?

Solana dApps work like other blockchain apps but have their own unique features. Here's a simpler breakdown:

Similarities:

  • They're decentralized apps, just like others on blockchain networks.
  • They operate with decentralized governance and operation.

Differences:

  • Solana uses its own special blockchain technology, unlike other platforms.
  • Building Solana dApps requires specific tools and languages like Rust and Anchor, different from other blockchain systems.

Focus on Solana DApps:

This guide explores Solana dApps, helping you understand and create your own cool apps on this powerful blockchain platform.

Solana DApp Use Cases:

  • Solana dApps are applications on the Solana blockchain.
  • They serve purposes such as finance, gaming, trading digital assets, and buying/selling digital items.
  • These dApps cater to various needs, including finance, gaming, and digital markets.

Some core pillers to build solana - dapp

Foundations of Running Things in a DApp:

Solana Tools:
- Rust
- Anchor
- Node.js
- Solana DApp Scaffold

Purpose Behind This:

The Solana Tools:
- These tools help prepare for building on a distributed ledger.
- For instance, Solana CLI is essential.
- Before diving into DApps, it's crucial to understand basic Solana CLI commands.
- Getting hands-on experience with web3 wallets and some test funds in those wallets helps interact with the live Devnet blockchain.

There are various ways to start building on Solana, but here, we'll focus on:

  • Setting up the local system to build on the Solana Devnet cluster. (A cluster is simply a single-node replication of the blockchain.)

Checkpoint-0 check environment

Before You Begin, Install the Following Tools:

  • Node
  • Yarn
  • Git
  • Rust
  • Solana Tools
  • Anchor

Verify These Installations:

yarn -V
node --version
git --version
rustc --version
solana -V
anchor --version
Enter fullscreen mode Exit fullscreen mode

Then, download the challenge to your computer and install dependencies by running:

git clone git@github.com:shivamSspirit/spl-tokens.git
cd spl-tokens
npm install (if error, use -f flag)
Enter fullscreen mode Exit fullscreen mode

Now, you have an Anchor Solana DApp.

About DApp:

DApp Features:

  • Connect to the DApp with the Devnet network using your Solana wallet (Phantom is recommended).
  • Mint NFT SPL tokens
  • Transfer tokens to another user or friend.

NOW

After setting up Solana tools and CLI, follow these steps:

  1. Visit: https://docs.solanalabs.com/cli/wallets/file-system
  2. Generate your file system wallet by using:
solana keygen
Enter fullscreen mode Exit fullscreen mode

This command will generate a keypair, which is an account keypair used for signing transactions.

  1. In a blockchain development environment, we mainly build and manage transactions.
  2. Type:
solana address
Enter fullscreen mode Exit fullscreen mode

You will receive your generated wallet public key, which looks like this:

OgxvVbhxGacHb92hzxogWQgVyuq4v4NdbYmPX6Hsv5Bz
Enter fullscreen mode Exit fullscreen mode

Now, you have a file system wallet ready to interact with Solana DApps.

The Development Pillars of Solana

Solana tools provide a comprehensive understanding of how Solana operates under the hood. It offers:

  • Wallet integration
  • Blockchain node replication
  • Low transaction costs
  • Faster transaction completion

With raw Solana development (the traditional approach), we focus on:

  • On-chain program processing
  • Utilizing the BPF loader

The Program Entrypoint

In the Solana runtime, only the Solana program entrypoint is visible and called.

This entrypoint accepts a generic byte array containing serialized program parameters, including the program ID, accounts, instruction data, and more. Each loader comes with its own wrapper macro, which:

  1. Exports the raw entrypoint.
  2. Deserializes the parameters.
  3. Calls a user-defined instruction processing function.
  4. Returns the result.

Parameter Deserialization

In each loader, there's a helper function that simplifies the deserialization of the program's input parameters into Rust types. The entrypoint macros then automatically invoke this deserialization helper.

Data Types

The loader's entrypoint macros invoke the program-defined instruction processor function with the following parameters:

program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8]
Enter fullscreen mode Exit fullscreen mode

NoTe-:
The program ID is the on-chain deployed program ID.

Accounts: If you're new to building on Solana, understand
that everything in Solana revolves around accounts.
Developers (users of web3) mainly manage accounts. There are
various types of accounts in Solana, which you'll grasp once
you delve deeper into the platform.

The general-purpose program instruction data that will be referenced by accounts.

Before you transition from the Ethereum ecosystem:

You need to understand that in Solana, programs (similar to smart contracts in Ethereum) separate logic from data. However, for both, we require accounts for creating logic and managing data.

Move To Modern

This is about traditional Solana development with native Rust.

Now, Armani provides us with wings by creating a super useful Solana development framework:

Anchor by Armani.

When building with native Rust, complexities arise with serializing and deserializing accounts data.

However, with Anchor, you gain access to many useful features for building Solana programs, including the capability to develop full-stack DApps using the Anchor framework.

Now root here and clone this repo

git clone git@github.com:shivamSspirit/spl-tokens.git
Enter fullscreen mode Exit fullscreen mode

💡 This is an Anchor DApp architecture.

At the start, you don't need to know about all files. As we progress, we will cover them.

Initially, keep in mind these files:

  1. The main setup for the DApp is automatically provided by Anchor.

    1. app
    2. programs
    3. test
    4. utils
    5. anchor.toml
  2. The first directory is app. This contains the client interaction with the Solana on-chain deployed program.

  3. programs: This directory contains the Solana program that we want to build for this DApp.

  4. test: This directory is for testing the on-chain program before deploying it to the client.

  5. utils: This directory contains utility helper methods we need to manage DApp functionality.

  6. anchor.toml is the DApp-runner file, which will build the DApp environment for:

    • Building
    • Deploying
    • Testing
    • Managing Solana programs.

The program we want to build for this guide is the SPL NFT mint and transfer.

You can learn more about Solana NFTs here.

As for the DApp features, let's walk through them:

Users will connect their Phantom wallet extension (compatible with Solana wallets) and switch their cluster to Devnet. Once connected, users can mint and transfer the NFT to another user.

Do you know what mint means? If not, it's important to learn.

Now, what are the important things you need to learn and be aware of?

First, from the smart contract side

As you are aware, Anchor provides us with good functionality.

It is built using Rust and abstracts some utilities in certain Rust macros and traits.

Reviewing Anchor-Compatible Solana Programs

The program will consist of three parts:

  1. The program module
  2. The account structs
  3. The declare ID macro

In the program module, you will utilize accounts data and manage that data (the business logic).

For the account structs, in Anchor, we can provide a context (like an object) of accounts for better validation of accounts running the DApp, eliminating the need to provide an array of accounts.

The declare ID macro creates an ID field that stores the address of your program. This is the first code you'll see when you generate a new Anchor project on your own.

// Use this import to gain access to common Anchor features
use anchor_lang::prelude::*;

// Declare an ID for your program
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

// Write your business logic here
#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
        Ok(())
    }
}

// Validate incoming accounts here
#[derive(Accounts)]
pub struct Initialize {}

Enter fullscreen mode Exit fullscreen mode

Go to anchor.toml and learn about it here.

This will generate a provider for all Anchor commands to interact with the Solana DApp.

[provider]
cluster = "devnet"                   # The cluster used for all commands.
wallet = "~/.config/solana/id.json"  # The keypair used for all commands.

Enter fullscreen mode Exit fullscreen mode

You know about wallets, right? This is our filesystem wallet path. Find it in your system and put the path of your generated keypair here.

Next, we have the cluster. You also know about the Solana blockchain node (a distributed state replication). We're discussing the test file here, so Anchor allows you to build a script for testing environments in Anchor Solana DApps.

Some features you need to set up to instruct the IDL generation of the backend system on what to add or not.

Next is the programs section:

tomlCopy code
[programs.devnet]
spltokens = "3ocdHhxYMDArmD5JXrAgrw1caHE3C76HvMD1dquEhX3S"
Enter fullscreen mode Exit fullscreen mode

This includes the addresses of the programs in the workspace.

The programs.devnet is used during testing on devnet where it's possible to load a program at genesis with the --bpf-program option on solana-test-validator.

NOW Dive into Program

Now, let's dive into our SPL NFT mint and transfer program.

First, ensure you've cloned and installed the dependencies on your own system. If not, set it up according to your operating system requirements.

Navigate to the program directory and then to spltokens/src/cargo.toml. This file contains the packages (dependencies) and crates you'll need to use and manage with imports in our Anchor programs.

Next, go to the lib.rs file. This serves as the entry point file for our Solana program. Here, you'll encounter three key components of an Anchor program, which you learned about earlier in this guide: imports, program ID, and program module.

Here's a snippet of what you'll see:

use anchor_lang::prelude::*;
pub mod instructions;
pub use instructions::*;
Enter fullscreen mode Exit fullscreen mode

These are some imports including primitives and local module imports needed to build our program.

Next, you'll encounter our program ID:

declare_id!("3ocdHhxYMDArmD5JXrAgrw1caHE3C76HvMD1dquEhX3S");
Enter fullscreen mode Exit fullscreen mode

Lastly, you'll see the program module named spltokens, which contains some instructional methods to build things around SPL tokens (both non-fungible and fungible). For our current focus on learning DApp architecture, we're interested in just two methods:

#[program]
pub mod spltokens {
    use super::*;

    pub fn mint_nft(ctx: Context<MintNFT>, name: String, symbol: String, uri: String) -> Result<()>
    {
        mint_nft::mint_nft(ctx, name, symbol, uri)
    }

    pub fn mint_token(ctx: Context<MintToken>, _decimals:u8, name: String, symbol: String, uri: String, amount: u64) -> Result<()>
    {
        mint_token::mint_token(ctx, _decimals, name, symbol, uri, amount)
    }

    pub fn transfer_tokens(ctx: Context<TransferToken>, amount: u64) -> Result<()>
    {
        transfer_token::transfer_tokens(ctx, amount)
    }
}
Enter fullscreen mode Exit fullscreen mode

These methods are responsible for minting NFTs, minting tokens, and transferring tokens, respectively.

use super::*;

This will inherit and apply all under-the-hood methods for building contract business logic.

Now, let's first move to...

 pub fn mint_nft(ctx: Context<MintNFT>, name: String, symbol: String, uri: String) -> Result<()> 
    {
        mint_nft::mint_nft(ctx, name, symbol, uri)
    }

Enter fullscreen mode Exit fullscreen mode

This is simply a Rust function, as in programming languages. It takes some parameters and assigns those parameters into instruction methods.

Now, let's navigate to the instruction instruction/mint_nft. Check lines 64 to 101. This section covers the account creation phase in the Anchor program. For NFTs, we need to build accounts around:

  • Solana native program
  • Token program
  • System program
  • Token metadata program
  • Metaplex program

We won't delve deeply into account creation in this DApp architecture guide. You'll need to experience use cases to build around accounts.

After the account phase (which takes input from the client and sends them to provide business logic to process), behind the scenes, accounts are assigned to Solana native programs to serve their required or lifetime information of that program.

Now, let's talk about the business logic:

The algorithm is as follows:

  • First, we receive some parameters and context.
  • In the first parameter, we can only provide account context.
  • Then, in the subsequent parameters, we put some general data and arguments that we process around NFT metadata (we won't explain what a master edition is here, just the mint and transfer mechanism).

For minting:

  • We need to create a CPI (Cross-Program Invocation) context to call the token program to create a token mint account to simply store the mint key and a reference for that token metadata.
  • We are setting up the context account and then making a CPI to the Metaplex program to create the metadata account for this NFT.

This is all about NFT minting as a developer.

💡 Now we are moving to spl token transfer

Let's discuss ins/transfer-tokens.

Here, we're simply creating another CPI context to call the token program methods for transferring SPL tokens under the token program environment

NOW we are Able to

To build and deploy your Solana program locally,

follow these steps:

  1. Run anchor build in the root folder named spl tokens.
  2. After a successful build, run solana config get to get your cluster configuration details.
  3. Open another terminal in the same folder and run solana-test-validator. This will start your local cluster.

Now that you're all set to deploy your Solana program:

  1. First, get some devnet SOL from the faucet by running solana airdrop 4.
  2. After a successful airdrop, run anchor deploy. This will give you a program ID, which contains all the information about your program in the Solana blockchain.

Next, update the program ID in your anchor.toml and Solana program entrypoint Rust file. Then, rebuild the Solana program and redeploy it.

Now, let's discuss testing:

  1. Navigate to the test directory in the root folder and then to the test file.
  2. Here, we'll engage in two test cases: mint NFT and transfer NFT.
  3. We'll set up a provider for the program and create a program API to send transactions through RPC requests to our Solana on-chain program. We'll fetch types from our Anchor build in the target folder.

Regarding the testing process:

  1. We'll create accounts and set up UMI client wrapper for building things around token metadata.
  2. Then, we'll curate our first transaction by calling our Solana program methods and sending accounts and required params to mint an NFT.

Moving on to the transfer test case:

  1. We'll set up the minted token mint public key and create required ATAs (Associated Token Accounts) and destination accounts to curate and send transactions to the deployed on-chain program.

This concludes the backend setup. Now,

Let's move to our DApp client interaction:

  1. Navigate to the app directory. This is a Solana DApp scaffold project architecture, preconfigured for building frontend using Next.js, TypeScript, and Solana-compatible wallet providers and package dependencies.
  2. Learn about this scaffold architecture and how to integrate it with the frontend. You can explore components like the NFT mint button and NFT card.
  3. Manage the IDL (Interface Description Language) generated by the Solana program to bridge the other side of the program: the client side.

Understanding Requirements and Similarities

How It's Similar to Anchor Tests
Remember the Anchor tests we discussed? They involved creating and transferring tokens using specific commands (RPC calls). We're going to use these same types of commands here.

Adding More Layers to Our DApp
We're enhancing our DApp by adding an extra layer. This isn't just for show – it helps display the current state of the DApp in the user interface.

First Steps: Setting Up
Before we dive in, let's make sure everything is ready:

  1. Check your computer's Node version.
  2. Install the Phantom extension and set up a new wallet.
  3. Go to the settings in your wallet and switch the cluster to Devnet – this is our playground for development.

Exploring the App Directory

Now, let's get to the heart of our setup – the Next.js framework we're using. It's based on a template provided by Solana Labs. In our project, you'll see a folder named "app" – this is where the magic happens.

Inside the "app" directory, our DApp combines several technologies:
• Solidity and Solang for the contract logic
• Next.js and Tailwind for the website part
• Anchor, Zustand, and Solana Wallet Adapter for connecting everything together
We'll be focusing on specific files in this directory:
• For integrating the contract:
◦ [idl] – This file describes the interface of our contract.
◦ [contracttypes] – Here, we define the types used in our contract.
• For running the DApp state:
◦ [_app.tsx] – The main file that runs our DApp.
◦ [context] – This manages the shared data within our app.
• For the user interface and helper functions:
◦ [ui view] – The visual part of our DApp.
◦ [component] – These are the building blocks of our user interface.

Setting Up Wallet, Provider, and Program API for Transactions

Integrating the Contract:
First, when you run anchor build for your contract, Anchor creates a "target" folder for your Solana program. In this folder, you'll find the deploy script, the IDL (Interface Description Language) file, and a directory for types.

IDL is like a blueprint for our program. It describes how our program should work.
We need to connect the blockchain part of our DApp (which runs in its own special environment) to the frontend (which uses different tools and languages). The IDL file acts as a bridge, using RPC protocols to make this connection.

RPC (Remote Procedure Call) is a set of methods we use to send requests to the Solana network.
The IDL file includes all the instructions and the program ID. The "types" directory gives us special Anchor types for sending these RPC calls.
Setting Up the Cluster and Wallet

To connect everything, we need:

  1. A cluster, which is like a specific area of the blockchain network where we send our transactions.

  2. A wallet for interacting with the DApp, which signs transactions and provides a public key.

By combining these, we set up an Anchor provider, which simplifies integrating the contract.
Using Wallet and Contexts

In our context directory, we define certain contexts and export them for use in other parts of our DApp. We need the network (our cluster) and the wallet (using Solana Wallet Adapter) for this. These are already set up, with configurations in their respective files.

In Next.js _app.tsx file

We use a main context provider in our Next.js _app file. Once we have the wallet and connection ready, we move to the next step.
Getting the Program API:
In the mintNftbutton component, we start by importing our contract's IDL.

import idl from "../../idl.json";

We then establish a connection, configure the wallet, and import necessary methods from various packages.

Set up the program id (the ID of our deployed Solana program).

const programId = new PublicKey(idl.metadata.address);

Use these hooks to access the connection and wallet states.

const { connection } = useConnection();
const wallet = useWallet();
const { publicKey, sendTransaction } = useWallet();```



Acquiring the Program API:
Create a provider with `new AnchorProvider(connection, wallet as any, opts);` using the wallet and connection. Then use the Anchor Program API to create an instance of our Solana program API.



```tsx
const getProgram = () => {
    const provider = new AnchorProvider(connection, wallet as any, opts);
    const program = new Program(idl as Idl, programId, provider);
    return program;
};
Enter fullscreen mode Exit fullscreen mode

Generating an RPC Call
Now, you can make an RPC call with the program:

const tx = await program.methods
        .mintNft(MetaData.name, MetaData.symbol, MetaData.uri)
        .accounts({
          signer: wallet.publicKey,
          mint: mintKeypair.publicKey,
          associatedTokenAccount,
          metadataAccount,
          masterEditionAccount,
          tokenProgram: TOKEN_PROGRAM_ID,
          associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
          tokenMetadataProgram: MPL_TOKEN_METADATA_PROGRAM_ID,
          systemProgram: anchor.web3.SystemProgram.programId,
          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
        })
        .signers([mintKeypair])
        .rpc();
Enter fullscreen mode Exit fullscreen mode

This is similar to a function call in rust:

  pub fn mint_nft(ctx: Context<MintNFT>, name: String, symbol: String, uri: String) -> Result<()> 
    {
        mint_nft::mint_nft(ctx, name, symbol, uri)
    }

Enter fullscreen mode Exit fullscreen mode

Remember, these operations are asynchronous because we're using Solana's Web3 JS.

we can use same setup for build our next instruction to transfer nft to another solana wallet

like this

const tx = await program.methods
.transferTokens(new BN(1))
.accounts({
from: publicKey,
fromAta: sellerTokenAccount,
toAta: buyerTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID
}).rpc({ skipPreflight: true });
Enter fullscreen mode Exit fullscreen mode

How you can use the Dapp-:

Go to app dir

Start the project:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000 with your browser to see the DApp.

Using the DAPP

Connect your wallet to the DAPP by clicking on the "Select Wallet" button.

You can switch the network of the dapp from the header.

Now click on Mint NFT, once you sign the transaction a Token Account will be created for the NFT and NFT will be minted in your wallet.

Image description

You can see the minted NFT and the NFT details on the screen

Image description

To transfer the NFT to another wallet, enter the wallet address in the input box, click SEND, and after signing the transaction your NFT will be transferred to another wallet.

After transfer the screen will look like this

Image description

Creating the similar DApp

  1. To create the similar Dapp you need to have pre knowledge of react and basic of spl token and solana NFTs.
  2. You can use the code from the repository and modify it according to your need.
  3. You can also use the code from the repository and deploy it on vercel or netlify to create your own DApp.

Top comments (0)