TypeScript SDK

The official TypeScript SDK for interacting with the rFlow protocol. Full type safety, PDA helpers, and comprehensive error handling.

Installation#

Install the SDK and its peer dependencies:

Terminal
$npm install @rflow/sdk @coral-xyz/anchor @solana/web3.js @solana/spl-token
Peer Dependencies
The SDK requires @coral-xyz/anchor ^0.32.0 and @solana/web3.js ^1.95.0 as peer dependencies.

Quick Start#

Initialize the client and start interacting with the protocol:

example.ts
1import { RFlowClient, SourceProtocol } from "@rflow/sdk";
2import { Connection, PublicKey } from "@solana/web3.js";
3
4// Create a read-only client (no wallet needed)
5const connection = new Connection("https://api.devnet.solana.com");
6const client = RFlowClient.readOnly(connection);
7
8// Get all available yield deals
9const deals = await client.yieldDeals.getAvailableDeals();
10console.log(`Found ${deals.length} available deals`);
11
12// Get protocol configuration
13const config = await client.getConfig();
14console.log(`Protocol fee: ${config?.feeBps / 100}%`);
15
16// For write operations, pass a wallet
17import { useWallet } from "@solana/wallet-adapter-react";
18const { publicKey, signTransaction, signAllTransactions } = useWallet();
19
20const clientWithWallet = new RFlowClient({
21 connection,
22 wallet: { publicKey, signTransaction, signAllTransactions },
23});
24
25// Create a new deal
26const instructions = await clientWithWallet.yieldDeals.createDeal({
27 receiptTokenMint: new PublicKey("..."),
28 receiptTokensAmount: 10_000_000_000, // 10,000 tokens (6 decimals)
29 principalValueAtLock: 10_000_000_000,
30 expectedYield: 150_000_000,
31 sellingPrice: 125_000_000,
32 durationDays: 90,
33 sourceProtocol: SourceProtocol.Kamino,
34 exchangeRateAtLock: 1_050_000, // 1.05
35});

Yield Deals#

The YieldDealClient provides methods for interacting with yield deals (receipt tokens like kUSDC, mSOL, jitoSOL).

Read Operations

typescript
1// Get a deal by ID
2const deal = await client.yieldDeals.getDeal(42);
3
4// Get a deal by PDA
5const dealByPda = await client.yieldDeals.getDealByPda(dealPda);
6
7// Get all deals with optional filters
8const allDeals = await client.yieldDeals.getAllDeals({
9 status: DealStatus.Active,
10 sourceProtocol: SourceProtocol.Kamino,
11});
12
13// Get available deals (status = Created)
14const available = await client.yieldDeals.getAvailableDeals();
15
16// Get deals by seller
17const myDeals = await client.yieldDeals.getDealsBySeller(myWallet);
18
19// Get deals by buyer
20const myInvestments = await client.yieldDeals.getDealsByBuyer(myWallet);

Write Operations

All write operations return TransactionInstruction[] that you can include in a transaction:

typescript
1// Create a deal
2const createIxs = await client.yieldDeals.createDeal({
3 receiptTokenMint: kUsdcMint,
4 receiptTokensAmount: 10_000_000_000,
5 principalValueAtLock: 10_000_000_000,
6 expectedYield: 150_000_000,
7 sellingPrice: 125_000_000,
8 durationDays: 90,
9 sourceProtocol: SourceProtocol.Kamino,
10 exchangeRateAtLock: 1_050_000,
11});
12
13// Buy a deal
14const buyIxs = await client.yieldDeals.buyDeal(
15 dealId,
16 sellerPaymentAccount,
17 treasuryAccount
18);
19
20// Cancel a deal (seller only, before purchase)
21const cancelIxs = await client.yieldDeals.cancelDeal(dealId);
22
23// Settle a deal (after expiry)
24const settleIxs = await client.yieldDeals.settleDeal(dealId, currentTokenValue);
25
26// Buyback a deal (seller early exit with penalty)
27const buybackIxs = await client.yieldDeals.buybackDeal(dealId, currentTokenValue);
28
29// Build and send transaction
30const tx = new Transaction().add(...createIxs);
31const signature = await sendTransaction(tx, connection);

Meteora LP Deals#

The MeteoraLpDealClient provides methods for Meteora CP-AMM LP fee deals. Lock your Position NFT and sell future fees.

Read Operations

typescript
1// Same API as YieldDealClient
2const deal = await client.meteoraDeals.getDeal(dealId);
3const available = await client.meteoraDeals.getAvailableDeals();
4const myDeals = await client.meteoraDeals.getDealsBySeller(myWallet);

Write Operations

typescript
1// Create a Meteora LP deal
2const createIxs = await client.meteoraDeals.createDeal({
3 positionNftMint: positionNftMint,
4 positionAccount: meteoraPositionPda,
5 pool: meteoraPoolPda,
6 tokenAMint: usdcMint,
7 tokenBMint: solMint,
8 feeAAtLock: 0,
9 feeBAtLock: 0,
10 expectedFeeA: 500_000_000, // Expected USDC fees
11 expectedFeeB: 1_000_000_000, // Expected SOL fees
12 expectedFeeValueUsdc: 650_000_000, // Total value in USDC
13 sellingPrice: 500_000_000,
14 durationDays: 90,
15});
16
17// Buy a Meteora LP deal
18const buyIxs = await client.meteoraDeals.buyDeal(
19 dealId,
20 sellerPaymentAccount,
21 treasuryAccount
22);
23
24// Claim fees (buyer only, during active deal)
25const claimIxs = await client.meteoraDeals.claimFees({
26 dealId,
27 meteoraProgram: METEORA_PROGRAM_ID,
28 meteoraPosition: positionPda,
29 meteoraPool: poolPda,
30 poolTokenAVault: tokenAVault,
31 poolTokenBVault: tokenBVault,
32});
33
34// Settle after expiry (returns NFT to seller)
35const settleIxs = await client.meteoraDeals.settleDeal(dealId);
36
37// Withdraw liquidity (seller only, after settlement)
38const withdrawIxs = await client.meteoraDeals.withdrawLiquidity({
39 dealId,
40 meteoraProgram: METEORA_PROGRAM_ID,
41 meteoraPosition: positionPda,
42 meteoraPool: poolPda,
43 poolTokenAVault: tokenAVault,
44 poolTokenBVault: tokenBVault,
45 poolAuthority: poolAuthorityPda,
46 eventAuthority: eventAuthorityPda,
47 tokenAProgram: TOKEN_PROGRAM_ID,
48 tokenBProgram: TOKEN_PROGRAM_ID,
49 tokenAAmountThreshold: 0,
50 tokenBAmountThreshold: 0,
51});
52
53// Split position (before creating a deal, to sell partial position)
54const splitIxs = await client.meteoraDeals.splitPosition({
55 sourceNftMint: sourcePositionNft,
56 sourcePosition: sourcePositionPda,
57 targetNftMint: newPositionNft,
58 targetPosition: newPositionPda,
59 meteoraPool: poolPda,
60 meteoraProgram: METEORA_PROGRAM_ID,
61 eventAuthority: eventAuthorityPda,
62 unlockedLiquidityPercentage: 50,
63 permanentLockedLiquidityPercentage: 50,
64 feeAPercentage: 50,
65 feeBPercentage: 50,
66 reward0Percentage: 50,
67 reward1Percentage: 50,
68});

PDA Helpers#

Helper functions to derive Program Derived Addresses:

typescript
1import {
2 findProtocolConfigPDA,
3 findYieldDealPDA,
4 findVaultPDA,
5 findMeteoraLpDealPDA,
6 findMeteoraVaultPDA,
7 PROGRAM_ID,
8} from "@rflow/sdk";
9
10// Protocol config PDA
11const [configPda, configBump] = findProtocolConfigPDA(PROGRAM_ID);
12
13// Yield deal PDA
14const [dealPda, dealBump] = findYieldDealPDA(dealId, PROGRAM_ID);
15
16// Token vault PDA (for locked receipt tokens)
17const [vaultPda, vaultBump] = findVaultPDA(dealPda, PROGRAM_ID);
18
19// Meteora LP deal PDA
20const [meteoraDealPda] = findMeteoraLpDealPDA(dealId, PROGRAM_ID);
21
22// Meteora NFT vault PDA
23const [nftVaultPda] = findMeteoraVaultPDA(meteoraDealPda, PROGRAM_ID);

Error Handling#

The SDK provides typed errors for better error handling:

typescript
1import {
2 RFlowError,
3 FetchError,
4 DealNotFoundError,
5 InvalidInputError,
6 InvalidDurationError,
7 parseAnchorError,
8 isAccountNotFoundError,
9 ERROR_CODES,
10} from "@rflow/sdk";
11
12try {
13 const deal = await client.yieldDeals.getDeal(999);
14} catch (error) {
15 if (error instanceof DealNotFoundError) {
16 console.log("Deal not found:", error.dealId);
17 } else if (error instanceof InvalidInputError) {
18 console.log("Invalid input:", error.message);
19 } else if (error instanceof InvalidDurationError) {
20 console.log("Invalid duration:", error.duration, "days");
21 console.log("Valid durations:", error.validDurations);
22 }
23}
24
25// Parse Anchor program errors
26try {
27 await sendTransaction(tx);
28} catch (error) {
29 const rflowError = parseAnchorError(error);
30 if (rflowError) {
31 console.log("Program error:", rflowError.code, rflowError.message);
32 }
33}
34
35// Check if account doesn't exist
36if (isAccountNotFoundError(error)) {
37 console.log("Account not found on chain");
38}

Types#

The SDK exports comprehensive TypeScript types:

typescript
1import type {
2 // Deal types
3 YieldDeal,
4 MeteoraLpDeal,
5 ProtocolConfig,
6
7 // Input types
8 CreateYieldDealInput,
9 CreateMeteoraLpDealInput,
10 ClaimMeteoraFeesInput,
11 DealFilters,
12
13 // Enums
14 DealStatus,
15 SourceProtocol,
16} from "@rflow/sdk";
17
18// Deal status enum
19enum DealStatus {
20 Created = 0, // Waiting for buyer
21 Active = 1, // Purchased, in progress
22 Settled = 2, // Ended, distributions complete
23 Cancelled = 3, // Cancelled before purchase
24 BoughtBack = 4 // Seller did early buyback
25}
26
27// Source protocol enum
28enum SourceProtocol {
29 // Lending
30 Kamino = 0,
31 MarginFi = 1,
32 Solend = 2,
33 Save = 3,
34 // Liquid Staking
35 Marinade = 4,
36 Jito = 5,
37 Blaze = 6,
38 Sanctum = 7,
39 Lido = 8,
40 // LP (Phase 2)
41 RaydiumLp = 9,
42 MeteoraLp = 10,
43 OrcaLp = 11,
44 // Fee Streams (Phase 3)
45 FeeStream = 12,
46}
Full Type Safety
The SDK is fully typed with TypeScript. Use your IDE's autocomplete to explore all available methods and types.