Skip to main content

Client Integration

In this guide, we will go through the steps to set up a local development environment for building onchain integrations with Lockup using TypeScript and Anchor's IDL.

caution

The following code examples are for demonstration purposes only and are not production-ready. They are intended to provide guidance on how to interact with the MerkleInstant program.

Dependencies

Download Types

First, download the TypeScript types for the MerkleInstant program from the GitHub release:

curl -L -o sablier_merkle_instant.ts \
https://github.com/sablier-labs/solsab/releases/download/v1.0.0/sablier_merkle_instant.ts

Install NPM Packages

Install the required Solana and Anchor packages:

bun add @coral-xyz/anchor@0.31.1 @solana/web3.js@1.98.2 bn.js@5.2.2

Setup

Import the necessary modules and types:

import * as anchor from "@coral-xyz/anchor";
import { Connection, PublicKey, Keypair } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { SablierMerkleInstant } from "./sablier_merkle_instant"; // Path to your downloaded types
import BN from "bn.js";

Set up the Anchor provider and program instance:

// Create connection to Solana cluster
const connection = new Connection("https://api.devnet.solana.com", "confirmed");

// Set up wallet (example using a keypair)
const wallet = new anchor.Wallet(yourKeypair);

// Create provider
const provider = new anchor.AnchorProvider(connection, wallet, {
commitment: "confirmed",
});

// Set the provider
anchor.setProvider(provider);

// Initialize the program (PROGRAM_ID is included in the types)
const program = new anchor.Program<SablierMerkleInstant>(
idl as SablierMerkleInstant, // Your IDL object
provider,
);

Craete an airdrop campaign

async function createAirdropCampaign() {
const creator = provider.wallet.publicKey;
// Some dummy parameters values
const merkleRoot = Array.from(Buffer.from("d52549cb072a1fcd052412fc80f678effe92aeeedccd1cae632c5c6e1de89379", "hex"));
const startTime = new BN(Math.floor(Date.now()));
// 30 days later
const expirationTime = startTime.add(new BN(24 * 60 * 60 * 30));
const ipfsCid = "bafkreiecpwdhvkmw4y6iihfndk7jhwjas3m5htm7nczovt6m37mucwgsrq";
const name = "My Airdrop Campaign";
// Total amount to be airdropped to all recipients
const aggregateAmount = new BN(10000 * 10 ** 6); // 10,000 tokens (assuming 6 decimals)
// Number of recipients
const recipientCount = 10;

const airdropTokenMint = new PublicKey("YOUR_TOKEN_MINT_HERE");

// Set a higher compute unit limit so that the transaction doesn't fail
const increaseCULimitIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 });

const txSignature = await merkleInstantProgram.methods
.createCampaign(merkleRoot, startTime, expirationTime, name, ipfsCid, aggregateAmount, recipientCount)
.signers([signerKeys])
.accounts({
airdropTokenMint,
airdropTokenProgram: TOKEN_PROGRAM_ID,
creator,
})
.preInstructions([increaseCULimitIx])
.rpc();

console.log("Airdrop campaign created successfully!");
console.log("Transaction signature:", txSignature);
}

Claim from an airdrop campaign

async function claimFromAirdropCampaign(campaign: PublicKey, merkleProof: number[][]) {
const claimer = provider.wallet.publicKey;
const recipient = claimer; // The recipient of the airdrop

// The index from the Merkle tree
const index = 1;
// Amount allocated to the recipient
const amount = new BN(1000 * 10 ** 6); // 1000 tokens (assuming 6 decimals)

// Chainlink program and feed addresses
const chainlinkProgram = new PublicKey("HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny");
const chainlinkSolUsdFeed = new PublicKey("99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR");

const airdropTokenMint = new PublicKey("YOUR_TOKEN_MINT_HERE");

const txSignature = await this.merkleInstant.methods
.claim(index, amount, merkleProof)
.accounts({
airdropTokenMint,
airdropTokenProgram: TOKEN_PROGRAM_ID,
campaign,
chainlinkProgram,
chainlinkSolUsdFeed,
claimer,
recipient,
})
.rpc();

console.log("Airdrop claimed successfully!");
console.log("Transaction signature:", txSignature);
}

For more examples and advanced usage, refer to the SolSab repository test files and scripts.