Skip to main content

Client Integration with Lockup

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. For more examples and advanced usage, refer to the SolSab repository test files and scripts.

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 Lockup program.

note

Make sure your wallet has enough SOL and SPL tokens on Devnet (used by the examples in this guide).

Dependencies

Download the program IDL & Types

First, download the IDL and the TypeScript types for the Lockup program from the GitHub release. For this example, we will place the types under the target directory.

# Create target directories
mkdir -p target/idl
mkdir -p target/types
# Download the IDL to the target directory
curl -L -o target/idl/sablier_lockup.json \
https://github.com/sablier-labs/solsab/releases/download/v0.1/sablier_lockup.json

and:

# Download the types to the target directory
curl -L -o target/types/sablier_lockup.ts \
https://github.com/sablier-labs/solsab/releases/download/v0.1/sablier_lockup.ts

Install NPM Packages

Next, install the required Solana and Anchor packages:

bun add @coral-xyz/anchor@0.31.1 @solana/web3.js@1.98.2 @solana/spl-token@0.4.13

Setup

Create a file:

touch stream-management.ts

Then, import the necessary modules and types into it.

import { BN } from "@coral-xyz/anchor";
import * as anchor from "@coral-xyz/anchor";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { ComputeBudgetProgram, PublicKey } from "@solana/web3.js";
import { type SablierLockup } from "./target/types/sablier_lockup";

Set up the Anchor provider and program instance:

let anchorProvider: anchor.AnchorProvider;
let lockupProgram: anchor.Program<SablierLockup>;
let signerKeys: anchor.web3.Keypair;

async function setUp() {
// Configure the Anchor provider
anchorProvider = anchor.AnchorProvider.env();
anchor.setProvider(anchorProvider);

// Declare the lockup program based on the downloaded IDL
lockupProgram = anchor.workspace.SablierLockup as anchor.Program<SablierLockup>;

// Define the signer wallet
signerKeys = (anchorProvider.wallet as anchor.Wallet).payer;
}

Withdraw from a Stream

Using withdraw

The following code calls the withdraw instruction from the lockup program:

async function withdrawFromStream(streamNftMint: PublicKey, amount: BN) {
// Ensure the set up is done
await setUp();

const signer = signerKeys.publicKey;
const streamRecipient = signer;
const withdrawalRecipient = signer;
const depositedTokenMint = new PublicKey("DEPOSITED_TOKEN_MINT_HERE");

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

// Call the `withdraw` instruction
const txSignature = await lockupProgram.methods
.withdraw(amount)
.accounts({
chainlinkProgram,
chainlinkSolUsdFeed,
depositedTokenMint,
depositedTokenProgram: TOKEN_PROGRAM_ID,
nftTokenProgram: TOKEN_PROGRAM_ID,
signer,
streamNftMint,
streamRecipient,
withdrawalRecipient,
})
.rpc();

console.log("Withdrawal successful!");
console.log("Transaction signature:", txSignature);
}

Make sure to call the withdrawFromStream function to execute the withdrawal on-chain:

// Withdraw 100 tokens (assuming 6 decimals)
const amountToWithdraw = new BN(100 * 10 ** 6);
withdrawFromStream("YOUR_STREAM_NFT_MINT_HERE", amountToWithdraw);

Execute the below command (change ANCHOR_WALLET if your wallet config is located at a different path):

ANCHOR_WALLET=~/.config/solana/id.json \
ANCHOR_PROVIDER_URL="https://api.devnet.solana.com" \
bun run stream-management.ts

Using withdrawMax

The following code withdraws the maximum available amount from a stream:

async function withdrawMaxFromStream(streamNftMint: PublicKey) {
// Ensure the set up is done
await setUp();

const signer = signerKeys.publicKey;
const streamRecipient = signer;
const withdrawalRecipient = signer;
const depositedTokenMint = new PublicKey("DEPOSITED_TOKEN_MINT_HERE");

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

// Call the `withdrawMax` instruction
const txSignature = await lockupProgram.methods
.withdrawMax()
.accounts({
chainlinkProgram,
chainlinkSolUsdFeed,
depositedTokenMint,
depositedTokenProgram: TOKEN_PROGRAM_ID,
nftTokenProgram: TOKEN_PROGRAM_ID,
signer,
streamNftMint,
streamRecipient,
withdrawalRecipient,
})
.rpc();

console.log("Max withdrawal successful!");
console.log("Transaction signature:", txSignature);
}

Make sure to call the withdrawMaxFromStream function to execute the withdrawal on-chain:

withdrawMaxFromStream("YOUR_STREAM_NFT_MINT_HERE");

Execute the below command (change ANCHOR_WALLET if your wallet config is located at a different path):

ANCHOR_WALLET=~/.config/solana/id.json \
ANCHOR_PROVIDER_URL="https://api.devnet.solana.com" \
bun run stream-management.ts

Cancel a Stream

The following code cancels an existing stream:

async function cancelStream(streamNftMint: PublicKey) {
// Ensure the set up is done
await setUp();

// The sender of the stream
const sender = signerKeys.publicKey;
const depositedTokenMint = new PublicKey("DEPOSIT_TOKEN_MINT_HERE");

// Call the `cancel` instruction
const txSignature = await lockupProgram.methods
.cancel()
.accounts({
depositedTokenMint,
depositedTokenProgram: TOKEN_PROGRAM_ID,
sender,
streamNftMint,
})
.rpc();

console.log("Stream canceled successfully!");
console.log("Transaction signature:", txSignature);
}

Make sure to call the cancelStream function to execute the cancellation on-chain:

cancelStream("YOUR_STREAM_NFT_MINT_HERE");

Execute the below command (change ANCHOR_WALLET if your wallet config is located at a different path):

ANCHOR_WALLET=~/.config/solana/id.json \
ANCHOR_PROVIDER_URL="https://api.devnet.solana.com" \
bun run stream-management.ts