This part details the step-by-step algorithm for implementing a Solidity Solang program for NFT minting and transfer, where the NFT mint authority is a Program Derived Address (PDA).
illustration
b
Testing NFT Mint Program
  • Set up and configure the testing environment for the NFT minting program.
  • Create and mint SPL-tokens (NFTs) using Solidity.
  • Write and execute test cases for the Solidity code.
  1. Modify package.json:

    • Navigate to the package.json file and update the dependencies:
      "dependencies": {
          "@coral-xyz/anchor": "^0.28.0",
          "@metaplex-foundation/js": "^0.19.4",
          "@solana/spl-token": "^0.3.8",
          "@solana/web3.js": "^1.78.4",
          // other dependencies
      }
      
  2. Install Dependencies:

    • Run npm install in the terminal to install the necessary dependencies.
  1. Update anchor.toml for Testing:
    • Add a script for running tests:
      [scripts]
      test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
      
    • This script is responsible for executing tests located in the test folder.
  1. Import Dependencies:

    • Begin by importing required modules and classes at the top of your test file:
     import * as anchor from "@coral-xyz/anchor";
     import { Program } from "@coral-xyz/anchor";
     import { PdaMintAuthority } from "../target/types/pda_mint_authority";
     import {
       Keypair,
       PublicKey,
       SystemProgram,
       SYSVAR_RENT_PUBKEY,
     } from "@solana/web3.js";
     import { Metaplex } from "@metaplex-foundation/js";
     import {
       ASSOCIATED_TOKEN_PROGRAM_ID,
       getAssociatedTokenAddressSync,
       TOKEN_PROGRAM_ID,
     } from "@solana/spl-token";
  1. Initialize Testing Framework:

    • Set up the testing framework:
     describe("pda-mint-authority", () => {
       // Test cases will go here
     });
  1. Configuring the Provider:

    • Set up provider and key pairs:
     const provider = anchor.AnchorProvider.env();
     anchor.setProvider(provider);
     const mintKeypair = anchor.web3.Keypair.generate();
     const wallet = provider.wallet;
     const connection = provider.connection;
     const program = anchor.workspace
       .PdaMintAuthority as Program<PdaMintAuthority>;
  1. Deriving PDA for Data Account:

    • Derive the Program Derived Address (PDA):
     const [dataAccountPDA, bump] = PublicKey.findProgramAddressSync(
       [Buffer.from("mint_authority")],
       program.programId
     );
  1. Defining NFT Metadata:

    • Specify metadata for the NFT:
     const nftTitle = "purple lamb";
     const nftSymbol = "lamb";
     const nftUri = "https://example.com/nft.json";
  1. Initializing Data Account:

    • Write a test to initialize the data account:
     it("Is initialized!", async () => {
       const tx = await program.methods
         .new([bump])
         .accounts({ dataAccount: dataAccountPDA })
         .rpc();
       console.log("Transaction signature", tx);
     });
  1. Creating and Minting NFT Token:

    • Implement a test case for creating and minting the NFT:
    • the createTokenMint is from our pda-mint-auth program
     it("Create an NFT!", async () => {
       const metaplex = Metaplex.make(connection);
       const metadataAddress = await metaplex
         .nfts()
         .pdas()
         .metadata({ mint: mintKeypair.publicKey });

       const tx = await program.methods
         .createTokenMint(
           dataAccountPDA, //the freeze authority
           0, // 0 decimals for NFT
           nftTitle, // NFT name
           nftSymbol, // NFT symbol
           nftUri // NFT URI
         )
         .accounts({
           payer: wallet.publicKey,
           mint: mintKeypair.publicKey,
           metadata: metadataAddress,
           mintAuthority: dataAccountPDA,
           rentAddress: SYSVAR_RENT_PUBKEY,
           metaplexId: new PublicKey(
             "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
           ),
         })
         .signers([mintKeypair])
         .rpc({ skipPreflight: true });
       console.log("Your transaction signature", tx);
     });
  1. Minting NFT to Wallet:

    • Write a test to mint NFT to a wallet:
    • the mintTo is from our pda-mint-auth program
     it("Mint the NFT to your wallet!", async () => {
       // Derive wallet's associated token account address for mint
       const tokenAccount = getAssociatedTokenAddressSync(
         mintKeypair.publicKey,
         wallet.publicKey
       );
       const tx = await program.methods
         .mintTo()
         .accounts({
           pdaAccount: dataAccountPDA,
           payer: wallet.publicKey,
           tokenAccount: tokenAccount,
           owner: wallet.publicKey,
           mint: mintKeypair.publicKey,
         })
         .rpc({ skipPreflight: true });
       console.log("Your transaction signature", tx);
     });
  • Add Metadata Program ID:

    • Add the following code to anchor.toml:
      [[test.validator.clone]]
      address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
      
  • This configures the Metaplex Metadata program ID for the tests.

With these steps, you'll have set up the development environment, configured the test script, and written tests to ensure your NFT minting program functions correctly. The next lesson will cover building, deploying, and testing the program in detail.