Solana NFT Candy Factory

repository·main·Indexed 43 days ago

https://github.com/kevinfaveri/solana-candy-factory

A tool for developers to fork, customize, and deploy Candy Machine mint applications to custom domains. It abstracts Solana and Metaplex interactions into CLI commands. Note: This project is outdated as it only implements Candy Machine V1, which has been deactivated by Metaplex.

Tokens
6.3K
Snippets
23
Records
27
Agent score
55%

What's inside Solana Candy Factory

  1. Important: This project is outdated

    main

    WARNING

    This repository is currently outdated as it only implements Candy Machine V1, which has been deactivated by Metaplex.

    If you need to work with Candy Machine V2, it is recommended to:

    • Submit a Pull Request to this repository to add CM2 support.
    • Use the official Metaplex example app.
    • If you specifically need the old version of this repository (pre-rework), use the old_repo branch: https://github.com/kevinfaveri/solana-candy-factory/tree/old_repo.
  2. Set up the Devnet development environment

    main

    To quickly set up a local development environment on Solana Devnet, use the setup-dev command.

    What this command does:

    • Creates a new Solana wallet.
    • Airdrops SOL to that wallet.
    • Uploads resources to the Devnet Metaplex program.
    • Automatically generates a .env.local file containing the start date, candy machine addresses, and treasury addresses.

    ⚠️ WARNING: Nuke Solution Running this command will replace your existing Solana devwallet at ~/.config/solana/candyfactory-devnet.json and overwrite your existing .env.local file. It is a complete reset of the development environment.

    Requirements:

    • You must have your NFT sources ready in the nft-sources folder.
    • Files must follow the naming convention starting with 0.json and 0.png.

    Workflow:

    1. Run setup: yarn setup-dev
    2. Run the dev server: yarn dev (starts the NextJS server with wallet connection, minting UI, and countdown features).
    yarn setup-dev
    
    yarn dev
  3. Prerequisites for Solana NFT Candy Factory

    main

    Before setting up the project, ensure you have the following installed:

    1. Node.js & Yarn: Recent versions of both must be installed.
    2. Solana Command Line Toolkit: Follow the official Solana installation guide.
    3. Metaplex Command Line Utility: Follow the installation instructions here. Note that installing the Command Line Package is considered an advanced task.

    Note: This project is designed to work primarily in unix-based environments.

  4. Deploy to Solana Mainnet

    main

    To deploy your NFT collection to the Solana Mainnet, use the deploy-mainnet command.

    Deployment Process:

    1. Run yarn deploy-mainnet and follow the interactive prompts.
    2. You will be asked to import a Wallet PK. This wallet must have sufficient SOL and will be the recipient of the mint value.
    3. The command stores your wallet key at ~/.config/solana/candyfactory-mainnet.json (this path can be modified in setup-solana-mainnet.sh).

    Important Constraints:

    • No Incremental Uploads: You cannot upload NFTs in batches. You must upload the entire collection in one go. If you need to update your batch, you must delete the candy machine folder and start over.
    • Wallet Consistency: Ensure the wallet used for Metaplex uploading (yarn deploy-mainnet) is the same one used in the NFTs' creators.address[0] to ensure royalties are earned correctly.
    • Post-Deployment: After successful deployment, a .env.local.production file will be generated in the project root. You must add these values to your production hosting environment (e.g., Vercel Environment Variables).
    yarn deploy-mainnet
  5. Configure ReCaptcha support

    main

    To enable ReCaptcha for your minting app, add the following keys to your .env file:

    • NEXT_PUBLIC_RECAPTCHA_KEY: Your Google ReCaptcha client-side key.
    • RECAPTCHA_SECRET: Your Google ReCaptcha server-side secret key.

    You can generate these keys via your Google account at https://www.google.com/recaptcha/about/.

    If you do not wish to use ReCaptcha, simply use a standard button instead of the ReCaptcha button component in your frontend.

  6. Fixing Initializing Config Timeout Error during Metaplex upload

    main

    When using the Metaplex candy machine CLI upload command, a timeout error may occur during the initializing config step. This error looks like: Error: Transaction was not confirmed in 60.00 seconds. It is unknown if it succeeded or failed.

    If this happens, your deployment wallet might appear to have lost funds without the command completing. Because the transaction may have actually succeeded on-chain despite the timeout, you must manually recover the state to resume the upload.

    Recovery Steps:

    1. Identify the Transaction Hash: Locate the signature hash (HASH_HERE) from the error message.
    2. Inspect the Transaction: Go to https://solscan.io/tx/HASH_HERE to view the transaction details.
    3. Extract Account Values: Look for the Create Account instruction. Identify and save the values for the first two input accounts: NewAccount and Source.
    4. Create a Temporary Cache File: In your project's .cache folder, create a file named mainnet-beta-temp (with no file extension).
    5. Configure the Cache File: Populate the file with a JSON object using the values extracted from Solscan. Use the first 6 characters of the NewAccount value for the uuid field.
    6. Resume Upload: Re-run the upload command. It should now resume from the point of failure instead of restarting.
    {
       "program":{
          "uuid":"First 6 Characters of the NewAccount value",
          "config":"NewAccount Value"
       },
       "items":{
          
       },
       "env":"mainnet-beta",
       "cacheName":"temp",
       "authority":"Source Value"
    }
  7. Wait for transaction signature confirmation

    main

    awaitTransactionSignatureConfirmation is a utility to poll for a transaction's status. It uses a combination of WebSocket subscriptions (connection.onSignature) and REST polling (connection.getSignatureStatuses) to ensure the transaction is confirmed.

    Parameters:

    • txid: The transaction signature to monitor.
    • timeout: Timeout in milliseconds.
    • connection: The Solana Connection instance.
    • commitment: The commitment level (defaults to "recent").
    • queryStatus: If true, it will actively poll the REST API if the WebSocket doesn't resolve immediately.
    const status = await awaitTransactionSignatureConfirmation(
      txSignature,
      60000,
      connection,
      "confirmed",
      true
    );
  8. Get Candy Machine state

    main

    Use getCandyMachineState to fetch the current status of a Candy Machine. It returns an object containing the CandyMachine instance (with its ID, connection, and Anchor program), the number of itemsAvailable, itemsRedeemed, itemsRemaining, and the goLiveDate as a JavaScript Date object.

    Note: This function requires an anchorWallet to fetch the program IDL from the blockchain.

    const state = await getCandyMachineState(
      anchorWallet,
      candyMachineId,
      connection
    );
    console.log(state.itemsRemaining);
    console.log(state.goLiveDate);
  9. Fetch the Candy Machine hash table with fetchHashTable()

    main

    Use fetchHashTable to retrieve the list of mint hashes associated with a specific Candy Machine ID. This function queries the Metaplex Metadata Program to find accounts matching the provided hash.

    Parameters:

    • hash (string): The Candy Machine ID.
    • metadataEnabled (boolean, optional):
      • If true, returns the full metadata objects.
      • If false (or omitted), returns only the mint addresses.

    Returns:

    • Promise<any[]>: An array of metadata objects or mint addresses.
    import { fetchHashTable } from './path-to-hook';
    
    // To get just the mint addresses:
    const mints = await fetchHashTable('CANDY_MACHINE_ID');
    
    // To get the full metadata:
    const metadata = await fetchHashTable('CANDY_MACHINE_ID', true);
  10. Fetch the list of candy machine holders with fetchHolderList()

    main

    Use fetchHolderList(hash: string) to retrieve a Set<string> containing the addresses of users who hold tokens minted from a specific Candy Machine.

    This function works by:

    1. Querying the MetadataProgram for accounts matching the provided mint hash.
    2. Iterating through metadata accounts to find the associated mint.
    3. Using getTokenLargestAccounts to identify token holders.
    4. Filtering out addresses that belong to known marketplaces (defined in allMarkets).

    Note: This function relies on the NEXT_PUBLIC_SOLANA_RPC_HOST environment variable to establish a connection to the Solana network.

    import { fetchHolderList } from './path-to-hook';
    
    const holders = await fetchHolderList('YOUR_CANDY_MACHINE_HASH');
    console.log(holders); // Set<string>
  11. Send a single transaction with automatic signing and confirmation

    main

    The sendTransaction function simplifies sending a single transaction by handling instruction aggregation, blockhash fetching, signing (via the provided wallet), and awaiting confirmation.

    Parameters:

    • connection: Solana Connection object.
    • wallet: The wallet object (must have a publicKey and signTransaction method).
    • instructions: An array of TransactionInstruction objects.
    • signers: An array of Keypair objects required for the transaction.
    • awaitConfirmation: Boolean. If true, the function waits for the transaction to be confirmed (default: true).
    • commitment: Solana commitment level (default: 'singleGossip').
    • includesFeePayer: If true, the wallet.publicKey is NOT automatically added as a signer. If false (default), the wallet.publicKey is added as the fee payer.
    • block: (Optional) An object containing blockhash and feeCalculator to reuse a specific blockhash.
    const { txid, slot } = await sendTransaction(
      connection,
      wallet,
      instructions,
      signers,
      true, // awaitConfirmation
      'confirmed'
    );
  12. Manage the hash table state with useHashTable()

    main

    The useHashTable React hook provides a managed way to fetch and store the Candy Machine hash table, including loading states and error handling via toasts.

    Parameters:

    • candyMachineId (string): The ID of the Candy Machine to query.
    • metadataEnabled (boolean): Whether to fetch full metadata or just mint addresses.

    Returns an object containing:

    • hashTable (any[]): The current list of retrieved hashes or metadata.
    • isLoading (boolean): Indicates if the fetch operation is in progress.
    • getHashTable (function): An async function to trigger the fetch process.

    Note: If candyMachineId is empty, the hook will trigger a toast error: "Please type the Candy Machine ID in the input box."

    import { useHashTable } from './path-to-hook';
    
    function MyComponent() {
      const { hashTable, isLoading, getHashTable } = useHashTable('CANDY_MACHINE_ID', false);
    
      return (
        <div>
          <button onClick={getHashTable} disabled={isLoading}>
            {isLoading ? 'Loading...' : 'Fetch Hashes'}
          </button>
          <ul>
            {hashTable.map((hash) => (
              <li key={hash}>{hash}</li>
            ))}
          </ul>
        </div>
      );
    }