user_claim

This is the pseudo-code for holder claim using @solana /web3.js in pure JavaScript.

import { PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
import { Buffer } from 'buffer';
import { FEE_RECEIVER, PROGRAM_ID } from '../utils/constants';
import {
    ASSOCIATED_TOKEN_PROGRAM_ID,
    createAssociatedTokenAccountInstruction,
    createCloseAccountInstruction,
    createInitializeAccountInstruction,
    getAssociatedTokenAddressSync,
    NATIVE_MINT,
    TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import { sendAndConfirmTx } from '../utils/conn';
import { getClaimAuthAddress, getConfigAddress, getUserStateAddress } from '../utils/pda';
import { generateRandomSeed } from '../utils/tools';

const discriminator = Buffer.from([178, 17, 203, 100, 110, 186, 223, 38]);
const closeDiscriminator = Buffer.from([127, 206, 172, 187, 146, 179, 215, 194]);

export const userClaim = async (connection, wallet, mintAddress, claimMint, userMintAccount, claimTokenProgram) => {
    const instructionData = discriminator;
    const mint = new PublicKey(mintAddress);

    const instructions = [];

    // Instruction: Create userClaimAccount
    let userClaimAccount;
    if (claimMint.equals(NATIVE_MINT)) {
        const seed = generateRandomSeed(24);
        userClaimAccount = await PublicKey.createWithSeed(wallet.publicKey, seed, TOKEN_PROGRAM_ID);
        const createAccountIx = SystemProgram.createAccountWithSeed({
            fromPubkey: wallet.publicKey,
            basePubkey: wallet.publicKey,
            seed: seed,
            newAccountPubkey: userClaimAccount,
            lamports: 2039280,
            space: 165,
            programId: TOKEN_PROGRAM_ID,
        });
        instructions.push(createAccountIx);

        const initAccountIx = createInitializeAccountInstruction(userClaimAccount, NATIVE_MINT, wallet.publicKey);
        instructions.push(initAccountIx);
    } else {
        userClaimAccount = getAssociatedTokenAddressSync(claimMint, wallet.publicKey, false, claimTokenProgram);
        const accountInfo = await connection.getAccountInfo(userClaimAccount);
        if (!accountInfo) {
            const createAccountIx = createAssociatedTokenAccountInstruction(
                wallet.publicKey,
                userClaimAccount,
                wallet.publicKey,
                claimMint,
                claimTokenProgram,
            );
            instructions.push(createAccountIx);
        }
    }

    // accounts
    const claimAuthority = getClaimAuthAddress(mint);
    const userState = getUserStateAddress(wallet.publicKey, mint);
    const claimVault = getAssociatedTokenAddressSync(claimMint, claimAuthority, true, claimTokenProgram);
    const feeAccount = getAssociatedTokenAddressSync(claimMint, FEE_RECEIVER, false, claimTokenProgram);

    const accounts = [
        { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
        { pubkey: getConfigAddress(), isSigner: false, isWritable: false },
        { pubkey: claimAuthority, isSigner: false, isWritable: false },
        { pubkey: mint, isSigner: false, isWritable: false },
        { pubkey: claimMint, isSigner: false, isWritable: false },
        { pubkey: claimVault, isSigner: false, isWritable: true },
        { pubkey: userState, isSigner: false, isWritable: true },
        { pubkey: userMintAccount, isSigner: false, isWritable: false },
        { pubkey: userClaimAccount, isSigner: false, isWritable: true },
        { pubkey: FEE_RECEIVER, isSigner: false, isWritable: false },
        { pubkey: feeAccount, isSigner: false, isWritable: true },
        { pubkey: claimTokenProgram, isSigner: false, isWritable: false },
        { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
        { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    ];

    // user_claim instruction
    const instruction = new TransactionInstruction({
        keys: accounts,
        programId: PROGRAM_ID,
        data: instructionData,
    });
    instructions.push(instruction);

    // Instruction: Close userClaimAccount
    if (claimMint.equals(NATIVE_MINT)) {
        const closeAccountIx = createCloseAccountInstruction(userClaimAccount, wallet.publicKey, wallet.publicKey);
        instructions.push(closeAccountIx);
    }

    // send and confirm transaction
    return sendAndConfirmTx(connection, wallet, instructions, []);
};

export const closeUserStates = async (connection, wallet, mints) => {
    const instructions = [];

    for (const mint of mints) {
        const instructionData = closeDiscriminator;

        // accounts
        const claimAuthority = getClaimAuthAddress(mint);
        const userState = getUserStateAddress(wallet.publicKey, mint);

        const accounts = [
            { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
            { pubkey: claimAuthority, isSigner: false, isWritable: false },
            { pubkey: mint, isSigner: false, isWritable: false },
            { pubkey: userState, isSigner: false, isWritable: true },
        ];

        // create instruction
        const instruction = new TransactionInstruction({
            keys: accounts,
            programId: PROGRAM_ID,
            data: instructionData,
        });

        instructions.push(instruction);
    }

    // send and confirm transaction
    return sendAndConfirmTx(connection, wallet, instructions, []);
};

Last updated