Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.meteora.ag/llms.txt

Use this file to discover all available pages before exploring further.

These examples are based on the local stake-for-fee-sdk/ts-client/src/examples source and the public SDK surface.

Connect To A Vault

import StakeForFee from "@meteora-ag/m3m3";
import { Connection, PublicKey } from "@solana/web3.js";

const connection = new Connection(process.env.RPC_URL!, "confirmed");
const pool = new PublicKey("G2MRSjNjCbFUmMf32Z1aXYhy6pc1ihLyYg6orKedyjJG");

const feeVault = await StakeForFee.create(connection, pool);

console.log("vault", feeVault.feeVaultKey.toBase58());
console.log("stake mint", feeVault.accountStates.feeVault.stakeMint.toBase58());

Create A Fee Vault

import StakeForFee from "@meteora-ag/m3m3";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";

const pool = new PublicKey("...");
const stakeMint = new PublicKey("...");

const currentSlot = await connection.getSlot("confirmed");
const currentTimestamp = await connection.getBlockTime(currentSlot);

const tx = await StakeForFee.createFeeVault(
  connection,
  pool,
  stakeMint,
  payer.publicKey,
  {
    topListLength: 10,
    unstakeLockDuration: new BN(86_400),
    secondsToFullUnlock: new BN(604_800),
    startFeeDistributeTimestamp: new BN(currentTimestamp! + 10),
  },
);
createFeeVault fetches the DAMM v1 pool, infers the quote mint as the other pool mint, derives the vault/list/token accounts, creates the DAMM v1 lock escrow if missing, and returns one transaction.

Create A Fee Vault With Explicit Mints

const tx = await StakeForFee.createFeeVaultWithParams(
  connection,
  pool,
  payer.publicKey,
  stakeMint,
  quoteMint,
  {
    topListLength: 10,
    unstakeLockDuration: new BN(86_400),
    secondsToFullUnlock: new BN(604_800),
    startFeeDistributeTimestamp: new BN(currentTimestamp! + 10),
  },
);
Use createFeeVaultInstructions when you need to compose the vault creation instructions into a larger transaction builder.

Lock DAMM v1 LP To The Vault

The local SDK examples lock DAMM v1 LP with @meteora-ag/dynamic-amm-sdk after the Stake2Earn vault is created:
import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
import { deriveFeeVault, STAKE_FOR_FEE_PROGRAM_ID } from "@meteora-ag/m3m3";
import Decimal from "decimal.js";

const amm = await AmmImpl.create(connection, pool);
const feeVaultKey = deriveFeeVault(pool, STAKE_FOR_FEE_PROGRAM_ID);

const tx = await amm.lockLiquidity(feeVaultKey, lpAmount, owner.publicKey, {
  stakeLiquidity: {
    ratio: new Decimal(1),
  },
});
The lock escrow owner must be the Stake2Earn vault PDA. Fees from that locked LP flow into Stake2Earn distribution instead of the creator wallet.

Stake Tokens

import BN from "bn.js";

await feeVault.refreshStates();

const stakeAmount = new BN("1000000000");
const tx = await feeVault.stake(stakeAmount, owner.publicKey);
stake includes initializeStakeEscrow when needed. If you have just changed vault state in another transaction, call refreshStates() before building the stake transaction.

Read Stake And Claimable Balance

await feeVault.refreshStates();

const { stakeEscrow, unclaimFee } =
  await feeVault.getUserStakeAndClaimBalance(owner.publicKey);

if (stakeEscrow) {
  console.log("active stake", stakeEscrow.stakeAmount.toString());
  console.log("claimable token A", unclaimFee.feeA?.toString());
  console.log("claimable token B", unclaimFee.feeB?.toString());
}
For a top-list staker, the SDK calculates newly released fees from current vault and lock escrow state before returning unclaimFee.

Claim Fees

import { U64_MAX } from "@meteora-ag/m3m3";

const tx = await feeVault.claimFee(owner.publicKey, U64_MAX);
claimFee claims quote token fees up to maxFee. Any base/stake token fee is automatically added back to the user’s stake escrow.

Request Unstake

import { Keypair } from "@solana/web3.js";

const unstake = Keypair.generate();

const tx = await feeVault.unstake(
  stakeEscrow.stakeAmount,
  unstake.publicKey,
  owner.publicKey,
);

tx.partialSign(unstake);
Store the unstake.publicKey. It is required for cancelUnstake and withdraw.

Cancel Unstake

const tx = await feeVault.cancelUnstake(unstake.publicKey, owner.publicKey);
Canceling returns the requested amount to active stake and closes the Unstake account.

Withdraw Released Stake

const tx = await feeVault.withdraw(unstake.publicKey, owner.publicKey);
The transaction fails until the current on-chain timestamp is at or after the Unstake.release_at value.

Find User Vaults And Unstakes

const vaults = await StakeForFee.getAllStakedVaultByUser(
  connection,
  owner.publicKey,
);

const unstakeRecords = await StakeForFee.getUnstakeByUser(
  connection,
  owner.publicKey,
  feeVault.feeVaultKey,
);

Gotchas

GotchaRecommendation
claimFee returns one transactionSend the returned transaction directly; do not iterate over it.
unstake needs a new signerGenerate and partial-sign with the Unstake keypair.
Cached account stateCall refreshStates() before building transactions after recent vault mutations.
Top-list replacement accountsLet the SDK build stake/claim/unstake transactions unless you are comfortable supplying replacement stake escrows manually.
Quote-only user claimExpect only the quote token to leave the vault on claimFee; the stake/base token side is restaked.