Initialize Controller

Now that you understand the Controller's structure and purpose, let's create one on-chain. This process will establish your authority root for managing airdrops and fee collection.

Step-by-Step Breakdown

1. PDA Derivation
const [controllerPda] = await getControllerDerivedAddress(wallet.address);

Uses the same deterministic derivation covered earlier, ensuring consistent address generation.

2. Instruction Creation
const instruction = await getInitializeControllerInstructionAsync({
  authority: client.wallet,   // The signer and authority
  feeLamports: BigInt(5000),  // Customize your fee amount
});

// Derive the feeVault address (a PDA seeded with the controller)
const [feeVault, feeVaultBump] = await getControllerVaultAddress(controllerPda);

This instruction prepares all necessary metadata for initializing the controller on-chain, including the creation of the feeVault — a Program Derived Address (PDA) used to hold controller fees.

3. Transaction Building and Signing
const transactionMessage = await createTransactionMessageFromInstructions(
  client.rpc,
  client.wallet,
  [instruction]
);
const signedTransaction = await signTransactionMessageWithSigners(
  transactionMessage
);

Prepares the transaction for network transmission and signs it with the wallet.

4. Send and Confirm Transaction
await client.sendAndConfirmTransaction(signedTransaction, { commitment: "confirmed" });
const signature = getSignatureFromTransaction(signedTransaction);

console.log("signature:", signature);

Submits the signed transaction to the network and waits for confirmation.

✅ After confirmation, your Controller is active and ready to manage airdrops!

Complete Initialization Example

import { getControllerDerivedAddress, getInitializeControllerInstructionAsync } from "@dropsy/airdrop";
import { getSignatureFromTransaction, signTransactionMessageWithSigners } from "@solana/kit";
import { createClient } from "./client";
import { createTransactionMessageFromInstructions } from "./utils";

async function initializeController() {
    const client = await createClient();

    const [controllerPda, bump] = await getControllerDerivedAddress(client.wallet.address);

    const instruction = await getInitializeControllerInstructionAsync({
        authority: client.wallet,
        controller: controllerPda,
        feeLamports: BigInt(5000),
    });

    const transactionMessage = await createTransactionMessageFromInstructions(
        client.rpc,
        client.wallet,
        [instruction],
    );

    const signedTransaction = await signTransactionMessageWithSigners(
        transactionMessage
    );

    await client.sendAndConfirmTransaction(signedTransaction, { commitment: "confirmed" });
    
    const signature = getSignatureFromTransaction(signedTransaction);

    console.log("signature : ", signature)
    console.log('your controller address : ', controllerPda)
}

Key Details:

  • Fee Structure: The specified fee (5000 lamports) will be charged per airdrop operation
  • Atomic Operation: Creates both Controller and associated fee vault in one transaction
  • Gas Costs: Expect ~0.002 SOL for account initialization (rent-exempt minimum)