Meteora
  • Meteora: The most dynamic and sustainable liquidity layer on Solana
  • PRODUCT OVERVIEW
    • Meteora Liquidity Pools
      • DLMM Overview
        • What is DLMM?
        • DLMM Program
        • Dynamic Fees
        • Strategies & Use Cases
        • DLMM Farming Rewards
      • DLMM Launch Pool Overview
      • Dynamic AMM Overview
        • What is a Dynamic AMM Pool?
        • Dynamic AMM LP Fee and APY Calculation
        • Creating a Dynamic AMM Pool via the UI
        • Claiming Fees from Permanently Locked Liquidity
        • Dynamic AMM Stable Pools
        • Dynamic LST Pools
        • Additional yield from Dynamic Vaults
        • Dynamic AMM Farm Overview
      • DAMM v2 Overview
      • Memecoin Pool Overview
        • Memecoin Pool v2
          • What is Memecoin Pool v2?
        • Memecoin Pool v1
          • What is Memecoin Pool v1?
          • Permanently Locking Liquidity
      • Stake2Earn Pool Overview
        • What is a Stake2Earn Pool?
        • Stake2Earn for Launchpads
      • Multi-Token Stable Pool Overview
    • Alpha Vault Overview
    • Dynamic Vault Overview
      • What is a Dynamic Vault?
      • Dynamic Vault Program
      • Hermes - Meteora's Keeper
        • Algorithm to find optimal yield allocations
        • Rebalance crank
        • Operation fee calculation
      • Design Goals
      • Security
      • Dynamic Vaults Whitepaper
      • Dynamic Vaults Community Explainers
      • Affiliate Program for Dynamic Vault
        • Become an Affiliate Partner (Dynamic Vaults)
    • Dynamic Bonding Curve (DBC) Overview
      • What is the Dynamic Bonding Curve?
      • Customizable Pool Configuration
      • Bonding Curve Formula
      • DBC Migrator Keeper
    • Meteora’s Anti-Sniper Suite
  • INTEGRATION
    • DLMM Integration
      • DLMM SDK
        • DLMM TypeScript SDK
        • CPI Examples
      • DLMM API
      • Fetching information on locked liquidity in a DLMM
    • Dynamic AMM Pool Integration
      • Dynamic AMM SDK
        • Dynamic AMM TypeScript SDK
        • CPI Examples
      • Dynamic AMM API
        • Pool Info
        • Pool State
      • Setting Pool and Fee Config for Dynamic AMM Pools
      • Create Dynamic Pool with Timestamp/Slot Activation
      • Dynamic AMM - Farm Integration
    • DAMM v2 Integration
      • DAMM v2 SDK
        • DAMM v2 TypeScript SDK
        • DAMM v2 Rust SDK
      • Setting Pool and Fee Config for DAMM v2
      • Technical FAQ
    • Memecoin Pool Integration
      • Memecoin Pool v2 Integration
        • Setting Pool and Fee Config for Memecoin Pool v2
      • Memecoin Pool v1 Integration
        • TypeScript Code Examples
        • CPI Examples
        • Setting Pool and Fee Config for Memecoin Pool v1
        • Track permanently-locked liquidity in Memecoin Pool v1
        • Track Protocol Fee from swaps in Memecoin Pool v1
    • Stake2Earn Pool Integration
    • Dynamic Vault Integration
      • Using TypeScript-Client
      • Using Rust-Client
      • Using CPI
      • Vault API
        • Vault Info
        • Vault State
      • Vault Developer Resources
    • Alpha Vault Integration
      • Alpha Vault TypeScript SDK
      • Alpha Vault without Whitelist Setup
      • Alpha Vault with Whitelist Setup
    • Dynamic Bonding Curve (DBC) Integration
      • DBC SDK
        • DBC TypeScript SDK
        • DBC Rust SDK
      • DBC Fee Scheduler Formula
      • Program Repo
      • Technical FAQ
  • TOKEN LAUNCH POOLS
    • Steps to Create a Pool for a Token Launch
      • Create: DLMM Launch Pool
      • Create: Dynamic AMM Pool
      • Create: Memecoin Pool v1
      • Create: Stake2Earn Pool
      • Create: Pools with Alpha Vault
        • Create: DLMM Launch Pool with Alpha Vault
        • Create: Dynamic AMM Pool with Alpha Vault
        • Create: Memecoin Pool with Alpha Vault
        • Create: Stake2Earn Pool with Alpha Vault
    • Anti-Sniper Fee Suite for a Token Launch
  • Resources
    • Audits
    • Meteora Program IDs
    • Meteora APIs
    • Devnet Testing
    • Community Data Dashboards & Tools
    • Meteora Brand Assets
    • THE MASSIVE METEORA STIMULUS PACKAGE
      • Overview
      • 1. Dynamic Liquidity Market Maker (DLMM)
      • 2. Formation Of An LP Army DAO
      • 3. The 10% Stimulus Proposal
  • USER FAQ
    • Getting Started LPing
      • Supported Wallets
      • Prepare SOL
      • SOL required for Rent
      • What is Wrapped SOL?
      • What is an AMM?
      • What does it mean to provide liquidity?
      • How to swap to the tokens required for adding liquidity to a pool
      • How to quickly check if a token has any risks
      • Viewing your transaction history
      • My wallet has been compromised. What should I do?
    • Differences between DLMM and Dynamic Pools
    • DLMM FAQ
    • Dynamic AMM FAQ
      • How is the pool price of the token calculated in a Dynamic AMM?
      • What is a Meteora LP token?
      • How do I see fees earned on a Dynamic AMM Pool?
      • How to track your earnings for a Dynamic Pool?
      • What is Virtual Price in a Dynamic Pool?
      • How do LP tokens, fees, and virtual price work for Dynamic Pools?
      • Why must I add liquidity in non-stable Dynamic Pools using a 50:50 value ratio?
      • What is AMP in a Dynamic Pool with stable coins?
      • Why is the USDT-USDC pool not 1:1 in ratio of assets?
      • Can I create an LST, FX, or Multi-token pool using the Dynamic Pool creation tool?
    • Alpha Vault FAQ
    • Why is the token sometimes not picked up and tradable on Jupiter?
    • How do I create a new farm?
    • Video Tutorials to Get Started
      • LP Army Boot Camp
      • DLMM Strategy Sessions / Jam Sessions
  • Security and Risks
    • Risk of Impermanent Loss (IL)
    • Risk of depositing into an imbalanced pool / pool with price out of sync
    • Smart contract risk
    • Risk of a stablecoin depeg
    • Operational risk for dynamic vaults and pools
    • Lending risk for dynamic vaults and pools
  • legal
    • Terms of Service
    • Stake2Earn Terms of Service
Powered by GitBook
On this page
  • Summary
  • List of Sections
  • Getting Started
  • API
  • 1. Install dependencies and initialize StakeForFee Instance
  • 1.1 Install Dependencies
  • 1.2 Initialize StakeForFee Instance
  • 2. Code Examples to interact with StakeForFee
  • Stake
  • Get stake balance and claimable balance
  • Claim Fee
  • Unstake
  • Get unstake period (Seconds)
  • Cancel unstake
  • Withdraw
  • 3. How to create a Memecoin Pool with Stake2Earn Vault
  • Important Reminder:
  • 3.1 TypeScript Code Example
  • 3.2 CPI Example to initialize a Stake2Earn vault
  • 3.3 Script to deploy a Stake2Earn vault
  • 4. How to create a Dynamic AMM Pool (fixed fee %) with Stake2Earn vault
  • 5. Important Considerations
  • Stake2Earn staking rewards distribution start time
  • Difference between locking liquidity via Stake2Earn vs directly locking liquidity in the Memecoin Pool
  • How to find the Stake2Earn vault address and a user wallet's unique personal Stake Escrow address?
  • Other Considerations
  1. INTEGRATION

Stake2Earn Pool Integration

PreviousTrack Protocol Fee from swaps in Memecoin Pool v1NextDynamic Vault Integration

Last updated 25 days ago

Summary

Stake2Earn Pools are Dynamic AMM Memecoin Pools that are launched with the stake-to-earn mechanism. For more information, read .

StakeForFee is the technical term used in the docs to describe the Stake2Earn mechanism and program, while feeFarm refers to a Stake2Earn Vault.

  • Memecoin Pool: A Dynamic AMM Pool created with a fee scheduler and with initial liquidity perma-locked.

  • Stake2Earn Vault: Stake-to-earn farming mechanism and vault where top stakers can earn a share of fees from the locked liquidity.

  • Stake2Earn Pool: A Memecoin Pool with a Stake2Earn Vault.

List of Sections

Getting Started

  • Program ID: FEESngU3neckdwib9X3KWqdL7Mjmqk9XNp3uh5JbP4KP

API

1. Install dependencies and initialize StakeForFee Instance

Below are the steps to use the StakeForFee TypeScript SDK.

1.1 Install Dependencies

npm i @meteora-ag/m3m3 @coral-xyz/anchor @solana/web3.js @solana/spl-token @solana/spl-token-registry

1.2 Initialize StakeForFee Instance

import StakeForFee from "@meteora-ag/m3m3";
import { PublicKey } from "@solana/web3.js";
import { Wallet, AnchorProvider } from "@project-serum/anchor";

// Connection, Wallet, and AnchorProvider to interact with the network
const mainnetConnection = new Connection("https://api.mainnet-beta.solana.com");
const mockWallet = new Wallet(new Keypair());
const provider = new AnchorProvider(mainnetConnection, mockWallet, {
  commitment: "confirmed",
});
// Alternatively, to use Solana Wallet Adapter

const poolAddress = new PublicKey(
  "G2MRSjNjCbFUmMf32Z1aXYhy6pc1ihLyYg6orKedyjJG"
);
const m3m3 = await StakeForFee.create(connection, poolAddress);

2. Code Examples to interact with StakeForFee

In the following code, feeFarm refers to the Stake2Earn Vault.

Stake

const stakeAmount = new BN(
  1_000 * 10 ** feeFarm.accountStates.tokenAMint.decimals
); // 1,000 stake token (make sure you have enough balance in your wallet)
const stakeTx = await feeFarm.stake(stakeAmount, mockWallet.publicKey);
const stakeTxHash = await provider.sendAndConfirm(stakeTx); // Transaction hash

Get stake balance and claimable balance

await feeFarm.refreshStates(); // make sure to refresh states to get the latest data
const userEscrow = await feeFarm.getUserStakeAndClaimBalance(
  mockWallet.publicKey
);
const stakeBalance =
  userStakeEscrow.stakeEscrow.stakeAmount.toNumber() /
  10 ** feeFarm.accountStates.tokenAMint.decimals;
const claimableFeeA = fromLamports(
  userStakeEscrow.unclaimFee.feeA || 0,
  feeFarm.accountStates.tokenAMint.decimals
);
const claimableFeeB = fromLamports(
  userStakeEscrow.unclaimFee.feeB || 0,
  feeFarm.accountStates.tokenBMint.decimals
);

Claim Fee

const claimFeeTx = await feeVault.claimFee(
  mockWallet.publicKey,
  new BN(U64_MAX)
); // second param is max amount, so usually we just put max number BN.js can support
const claimfeeTxHash = await provider.sendAndConfirm(claimFeeTx); // Transaction hash

Unstake

const unstakeKeyPair = new Keypair();
const unstakeTx = await feeVault.unstake(
  userEscrow.stakeEscrow.stakeAmount,
  unstakeKeyPair.publicKey,
  mockWallet.publicKey
);
unstakeTx.partialSign(unstakeKeyPair); // Make sure to partial sign unstakeKeypair
const unstakeTxHash = await provider.sendAndConfirm(unstakeTx); // Transaction hash

Get unstake period (Seconds)

const unstakePeriodInSeconds =
  feeFarm.accountStates.feeVault.configuration.unstakeLockDuration.toNumber();

Cancel unstake

const cancelUnstakeTx = await feeFarm.cancelUnstake(
  unstakeKeyPair.publicKey,
  mockWallet.publicKey
);
const cancelUnstakeTxHash = await provider.sendAndConfirm(cancelUnstakeTx);

Withdraw

const withdrawTx = await feeFarm.withdraw(
  unstakeKeyPair.publicKey,
  mockWallet.publicKey
);
const withdrawTxHash = await provider.sendAndConfirm(withdrawTx);

3. How to create a Memecoin Pool with Stake2Earn Vault

Important Reminder:

You are recommended to configure your Stake2Earn staking rewards distribution start time (fee claim start time) to be approximately 48 hours after launch. This allows more time for total fee rewards to accumulate from trading activity in the memecoin pool. A bigger total fee reward would help make your Stake2Earn Vault look more appealing to potential stakers.

3.1 TypeScript Code Example

This code example includes the steps to:

  • Mint a token

  • Create dynamic vault and pool

  • Create Stake2Earn Vault

  • Lock user's LP to Stake2Earn Vault

import AmmImpl from "@mercurial-finance/dynamic-amm-sdk";
import { NATIVE_MINT } from "@solana/spl-token";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { StakeForFee } from "../stake-for-fee";
import {
  DEFAULT_KEYPAIR_PATH,
  DEVNET_URL,
  handleSendTransaction,
  initializeMintAndMint,
  loadKeypairFromFile,
} from "./utils";
import { createFeeVault, createPool, lockLiquidityToFeeVault } from "./actions";
import { U64_MAX } from "../stake-for-fee/constants";

const connection = new Connection(DEVNET_URL);
const poolConfigKey = new PublicKey(
  "BdfD7rrTZEWmf8UbEBPVpvM3wUqyrR8swjAy5SNT8gJ2"
);
const mintADecimal = 9;
const mintANativeAmountMultiplier = 10 ** mintADecimal;
const mintAmount = 10_000;
const stakeFarmAmount = 1_000;

async function createPoolAndInteractWithFeeVaultExample() {
  const keypair = loadKeypairFromFile(DEFAULT_KEYPAIR_PATH);
  console.log(`Wallet ${keypair.publicKey} connected`);

  const amountAToMint =
    BigInt(mintAmount) * BigInt(mintANativeAmountMultiplier);
  const amountAToDeposit =
    BigInt(mintAmount - stakeFarmAmount) * BigInt(mintANativeAmountMultiplier); // 1,000 reserve to stake
  const amountB = BigInt(1_000_000);

  console.log("Create mint A");
  const mintA = await initializeMintAndMint(
    connection,
    keypair,
    keypair,
    mintADecimal,
    amountAToMint
  );

  console.log("1. Create dynamic vaults and pool");
  const poolKey = await createPool(
    keypair,
    mintA,
    NATIVE_MINT,
    new BN(amountAToDeposit.toString()),
    new BN(amountB.toString()),
    poolConfigKey
  );

  const pool = await AmmImpl.create(connection, poolKey);

  console.log("2. Create fee vault");
  const currentSlot = await connection.getSlot("confirmed");
  const currentOnchainTimestamp = await connection.getBlockTime(currentSlot);
  // Number of top stakers
  const topListLength = 10;
  // Number of seconds to withdraw unstaked token
  const unstakeLockDuration = new BN(3600 * 24);
  // Number of seconds for the swap fee fully dripped to stakers
  const secondsToFullUnlock = new BN(3600 * 24 * 7);
  // Timestamp to start fee distribution / drip to stakers
  const startFeeDistributeTimestamp = new BN(currentOnchainTimestamp + 10); // delay 10 seconds to be able to claim

  await createFeeVault(
    poolKey,
    pool.poolState.tokenAMint,
    keypair,
    topListLength,
    unstakeLockDuration,
    secondsToFullUnlock,
    startFeeDistributeTimestamp
  );

  console.log("3. Lock user LP for fee vault");
  await lockLiquidityToFeeVault(poolKey, pool, keypair, 10_000); // 10_000 means 100% of LP is being lock

  console.log("4. Connect to the fee vault");
  const feeVault = await StakeForFee.create(connection, poolKey);

  console.log("5. Stake amount");
  const stakeAmount = new BN(
    (BigInt(stakeFarmAmount) * BigInt(mintANativeAmountMultiplier)).toString()
  ); // 1,000 stake token (make sure you have enough balance in your wallet)
  const stakeTx = await feeVault.stake(stakeAmount, keypair.publicKey);
  const stakeSignature = await handleSendTransaction(
    connection,
    stakeTx,
    keypair
  );
  console.log("Stake Signature", stakeSignature);

  console.log("6. Get stake balance");
  await feeVault.refreshStates();
  const userEscrow = await feeVault.getUserStakeAndClaimBalance(
    keypair.publicKey
  );
  const stakeBalance =
    userEscrow.stakeEscrow.stakeAmount.toNumber() /
    10 ** feeVault.accountStates.tokenAMint.decimals;
  console.log("Stake Balance", stakeBalance);
  const claimableFeeA =
    (userEscrow.unclaimFee.feeA.toNumber() || 0) /
    10 ** feeVault.accountStates.tokenAMint.decimals;
  console.log("Claimable Fee A", claimableFeeA);
  const claimableFeeB =
    (userEscrow.unclaimFee.feeB.toNumber() || 0) /
    10 ** feeVault.accountStates.tokenBMint.decimals;
  console.log("Claimable Fee B", claimableFeeB);

  console.log("7. Claim fee");
  const claimFeeTx = await feeVault.claimFee(
    keypair.publicKey,
    new BN(U64_MAX)
  );
  for (const [index, tx] of claimFeeTx.entries()) {
    const signature = await handleSendTransaction(connection, tx, keypair);
    console.log(`Claim Fee Signature ${index + 1}`, signature);
  }

  console.log("8. Unstake");
  const unstakeKeyPair = new Keypair();
  const unstakeTx = await feeVault.unstake(
    userEscrow.stakeEscrow.stakeAmount,
    unstakeKeyPair.publicKey,
    keypair.publicKey
  );
  const unstakeSignature = await handleSendTransaction(connection, unstakeTx, [
    unstakeKeyPair,
    keypair,
  ]);
  console.log("Unstake Signature", unstakeSignature);

  console.log("9. Cancel unstaked");
  const cancelUnstake = await feeVault.cancelUnstake(
    unstakeKeyPair.publicKey,
    keypair.publicKey
  );
  const cancelUnstakeSignature = await handleSendTransaction(
    connection,
    cancelUnstake,
    keypair
  );
  console.log("Cancel Unstake Signature", cancelUnstakeSignature);

  // ⚠️ This only works after unstake period is over
  console.log("10. Withdraw unstake");
  const withdrawUnstake = await feeVault.withdraw(
    unstakeKeyPair.publicKey,
    keypair.publicKey
  );
  const withdrawUnstakeSignature = await handleSendTransaction(
    connection,
    withdrawUnstake,
    keypair
  );
  console.log("Withdraw Unstake Signature", withdrawUnstakeSignature);
}

createPoolAndInteractWithFeeVaultExample()
  .then(() => console.log("Done"))
  .catch(console.error);

3.2 CPI Example to initialize a Stake2Earn vault

3.3 Script to deploy a Stake2Earn vault

Alternatively, we also provide a convenient script to deploy a new Stake2Earn vault.

Getting Started

Dependencies

Code Example

{
  "rpcUrl": "https://api.mainnet-beta.solana.com",
  "dryRun": false,
  "keypairFilePath": "keypair.json",
  "computeUnitPriceMicroLamports": 100000,
  "baseMint": "FvxPZWBViVsmzS11MGi3ybNGjTKChwdfXU3UWopBujTn",
  "quoteSymbol": "SOL",
  "m3m3": {
    "topListLength": 100,
    "unstakeLockDurationSecs": 25200,
    "secondsToFullUnlock": 86400,
    "startFeeDistributeTimestamp": 1737590400
  },
  "lockLiquidity": {
    "allocations": [
      {
        "percentage": 100,
        "address": "D2Yt1jtjjk6cPiwYKs6krtbjfjjYiQmYWbFtTrgL2WR2"
      }
    ]
  }
}

4. How to create a Dynamic AMM Pool (fixed fee %) with Stake2Earn vault

If you are creating the pool using the instruction:

  • initializeCustomizablePermissionlessConstantProductPool

  • createPermissionlessConstantProductPoolWithConfig2

    • Make sure you choose the config account that doesn't have any Dynamic Fee.

5. Important Considerations

Stake2Earn staking rewards distribution start time

  • You are recommended to configure your Stake2Earn staking rewards distribution start time (fee claim start time) to be approximately 48 hours after launch. This allows more time for total fee rewards to accumulate from trading activity in the memecoin pool. A bigger total fee reward would help make your Stake2Earn Vault look more appealing to potential stakers.

Difference between locking liquidity via Stake2Earn vs directly locking liquidity in the Memecoin Pool

  • User lock and Stake2Earn lock use the same lock mechanism on a Dynamic AMM / Memecoin Pool. But users and Stake2Eearn vaults have their own personal lock escrow account for the pool.

  • When a user permanently locks liquidity directly on the Memecoin Pool page, the user is locking the LP token to their own personal escrow account for the pool. Fees from this locked liquidity go to the user's wallet.

  • However, when a user locks via the Stake2Earn creation process, the user is locking the LP to their unique Stake2Earn Vault stake escrow account. Therefore, fees from this locked liquidity go to the Stake2Earn Vault, which then distributes fees to the top stakers.

How to find the Stake2Earn vault address and a user wallet's unique personal Stake Escrow address?

  • Click "Open explorer" and on the explorer page search for Vault and/or Stake Escrow fields to find the respective addresses.

Other Considerations

  • If you plan to use a multisig on the Meteora website, please make sure it is the SquadsX multisig, as that is the only type supported on Meteora website. Otherwise, you can't manage liquidity through the website.

  • There can only be one Stake2Earn Vault attached to each Memecoin Pool.

SDK:

NPM:

PDA seeds:

Mainnet API endpoint:

Devnet API endpoint:

API endpoint to get Stake2Earn vault info from pool address:

Use this example to to create a Memecoin Pool with Stake2Earn Vault:

Other examples:

Note: The following script is for deploying a new Stake2Earn vault only. To deploy a Memecoin Pool with permanently locked liquidity, please refer to .

Clone repo:

Config list to reference:

Readme:

Install Bun: You'll also need to run the scripts. Install it via . Then install the dependencies by running the command bun install

Note: You can also deploy a Memecoin Pool with a Stake2Earn Vault, as well as an if required.

CPI Example:

It will be fixed fee. Same applies to a Dynamic AMM pool created using the script in this repo:

Check using and make sure it returns no fee curve.

Use a wallet simulator (e.g. ) and paste the user's wallet address. Try to stake or unstake tokens in a Stake2Earn Vault.

here
Getting Started
Install dependencies and initialize StakeForFee instance
Code examples to interact with StakeForFee
How to create a Memecoin Pool with Stake2Earn vault
TypeScript Code Example
CPI example to initialize a Stake2Earn vault
Script to deploy a Stake2Earn vault
How to create a Dynamic AMM Pool (fixed fee %) with Stake2Earn vault
Important Considerations
https://github.com/MeteoraAg/stake-for-fee-sdk
https://www.npmjs.com/package/@meteora-ag/m3m3
https://github.com/MeteoraAg/stake-for-fee-sdk/blob/main/ts-client/src/stake-for-fee/helpers/pda.ts#L15
https://stake-for-fee-api.meteora.ag/swagger-ui/
https://devnet.stake-for-fee-api.meteora.ag/swagger-ui/
https://stake-for-fee-api.meteora.ag/swagger-ui/#/vault/filter_vaults
https://github.com/MeteoraAg/stake-for-fee-sdk/blob/main/ts-client/src/examples/index.ts
https://github.com/MeteoraAg/cpi-examples?tab=readme-ov-file
Memecoin Pool Integration
https://github.com/MeteoraAg/meteora-pool-setup
https://github.com/MeteoraAg/meteora-pool-setup/tree/main/config
https://github.com/MeteoraAg/meteora-pool-setup/blob/main/README.md
bun
bun installation
https://github.com/MeteoraAg/meteora-pool-setup/blob/main/config/create_m3m3_farm.json
Alpha Vault
https://github.com/MeteoraAg/cpi-examples/blob/main/programs/cpi-example/src/instructions/dynamic_amm_cpi/initialize_customizable_permissionless_pool.rs
https://github.com/MeteoraAg/meteora-pool-setup/tree/main
https://amm-v2.meteora.ag/swagger-ui/#/fee_config/get_config_associated_fee_configs
Sherlock extension
Logocpi-examples/programs/cpi-example/src/instructions/m3m3_cpi/initialize_vault.rs at main · MeteoraAg/cpi-examplesGitHub