2.0.0 • Published 2d ago
@meteora-ag/m3m3
Licence
ISC
Version
2.0.0
Deps
6
Size
2.6 MB
Vulns
0
Weekly
0
Meteora M3M3 SDK
Getting started
NPM: https://www.npmjs.com/package/@meteora-ag/m3m3
SDK: https://github.com/MeteoraAg/stake-for-fee-sdk
Discord: https://discord.com/channels/841152225564950528/864859354335412224
Install
- Install deps
npm i @meteora-ag/m3m3 @coral-xyz/anchor @solana/web3.js @solana/spl-token @solana/spl-token-registry
- 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);
- To interact with the StakeForFee
Deprecated
claimFeeandunstake. UseclaimFeeAndWithdrawFullinstead.createFeeVault,createFeeVaultWithParams,createFeeVaultInstructions,initializeStakeEscrow,getOrCreateStakeEscrowInstruction,stake,cancelUnstakeandMIN_LOCK_ESCROW_CLAIM_FEE_DURATION.
Warning
- Stop creating stake-for-fee vaults.
- Do not create a DAMM lock escrow owned by a stake-for-fee vault PDA, or lock LP into one, e.g. with
AmmImpl.lockLiquidityand the fee vault as owner.
- Full exit (deprecation)
Full exit for stakers after the program deprecation. Withdraw every ongoing unstake request, then claim all pending fees and withdraw the stake in one transaction with claimFeeAndWithdrawFull, then close the empty stake escrow to get the rent back. Once every staker has exited, anyone can close the vault.
// 1. Withdraw every ongoing unstake request. They no longer wait for the unstake lock duration.
// Once the stake escrow is closed, only unstake requests with zero amount are left, close them with `closeZeroUnstake` instead.
// Skip the ones created before program 0.1.1, they have no owner.
const { stakeEscrow: openStakeEscrow } =
await feeFarm.getUserStakeAndClaimBalance(mockWallet.publicKey);
const unstakeList = await StakeForFee.getUnstakeByUser(
connection,
mockWallet.publicKey,
feeFarm.feeVaultKey
);
for (const { publicKey: unstakeKey, account } of unstakeList) {
if (openStakeEscrow) {
const withdrawTx = await feeFarm.withdraw(unstakeKey, mockWallet.publicKey);
await provider.sendAndConfirm(withdrawTx);
} else if (!account.owner.equals(PublicKey.default)) {
const closeZeroUnstakeTx = await StakeForFee.closeZeroUnstake(
connection,
unstakeKey,
mockWallet.publicKey
);
await provider.sendAndConfirm(closeZeroUnstakeTx);
}
}
// 2. Claim all pending fees, then withdraw the whole stake amount.
// Skip it when there is no stake amount and no pending fees.
await feeFarm.refreshStates();
const { stakeEscrow, unclaimFee } = await feeFarm.getUserStakeAndClaimBalance(
mockWallet.publicKey
);
if (
stakeEscrow &&
(!stakeEscrow.stakeAmount.isZero() ||
!unclaimFee.feeA.isZero() ||
!unclaimFee.feeB.isZero())
) {
const claimFeeAndWithdrawFullTx = await feeFarm.claimFeeAndWithdrawFull(
mockWallet.publicKey
);
await provider.sendAndConfirm(claimFeeAndWithdrawFullTx);
}
// 3. Close the empty stake escrow, the rent goes back to the owner.
if (stakeEscrow) {
const closeStakeEscrowTx = await feeFarm.closeStakeEscrow(
mockWallet.publicKey
);
await provider.sendAndConfirm(closeStakeEscrowTx);
}
// 4. Close the vault, the top staker list and the full balance list, the rent goes to the vault creator. Anyone can close it.
// Precondition: all stake escrows of the vault are closed, and the vault has no stake amount, ongoing unstake amount or effective stake amount.
// The token vaults are not closed, so the locked fees stay permanently locked.
await feeFarm.refreshStates();
const { metrics, topStakerInfo } = feeFarm.accountStates.feeVault;
if (
metrics.totalStakeEscrowCount.isZero() &&
metrics.totalStakedAmount.isZero() &&
metrics.ongoingTotalPartialUnstakeAmount.isZero() &&
topStakerInfo.effectiveStakeAmount.isZero()
) {
const closeVaultTx = await feeFarm.closeVault(mockWallet.publicKey); // Fee payer
await provider.sendAndConfirm(closeVaultTx);
}
- Stake (deprecated)
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 and withdraw full
// Claims all pending stake token and quote token fees, then withdraws the whole stake amount without an unstake request.
// The stake token fee is transferred to the owner instead of being restaked.
// A stake escrow without stake amount can still claim its pending fees.
const claimFeeAndWithdrawFullTx = await feeVault.claimFeeAndWithdrawFull(
mockWallet.publicKey
);
const claimFeeAndWithdrawFullTxHash = await provider.sendAndConfirm(
claimFeeAndWithdrawFullTx
); // Transaction hash
- Claim Fee (deprecated, use
claimFeeAndWithdrawFull)
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 (deprecated, use
claimFeeAndWithdrawFull)
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) (deprecated)
const unstakePeriodInSeconds =
feeFarm.accountStates.feeVault.configuration.unstakeLockDuration.toNumber();
- Cancel unstake (deprecated)
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);
- Close stake escrow
// Permissionless. Closes a stake escrow without stake amount, pending fees and ongoing unstake amount, the rent goes back to the owner.
// Empty it with `withdraw` and `claimFeeAndWithdrawFull` first.
const closeStakeEscrowTx = await feeFarm.closeStakeEscrow(
stakeEscrowOwner, // Receives the rent
mockWallet.publicKey // Fee payer, defaults to the owner
);
const closeStakeEscrowTxHash = await provider.sendAndConfirm(
closeStakeEscrowTx
);
- Close zero unstake
// The owner closes an unstake request with zero amount, the rent goes back to the owner.
// Use it when the stake escrow is already closed, else `withdraw` closes the request too.
const unstakeList = await StakeForFee.getUnstakeByUser(
connection,
mockWallet.publicKey,
feeVaultKey
);
for (const { publicKey: unstakeKey, account } of unstakeList) {
if (!account.unstakeAmount.isZero()) continue;
const closeZeroUnstakeTx = await StakeForFee.closeZeroUnstake(
connection,
unstakeKey,
mockWallet.publicKey
);
await provider.sendAndConfirm(closeZeroUnstakeTx);
}
- Close vault
// Permissionless. Closes the fee vault, the top staker list and the full balance list, the rent goes to the vault creator.
// Precondition: all stake escrows of the vault are closed, and the vault has no stake amount, ongoing unstake amount or effective stake amount.
// The token vaults are not closed, so the locked fees stay permanently locked.
const closeVaultTx = await feeFarm.closeVault(mockWallet.publicKey); // Fee payer
const closeVaultTxHash = await provider.sendAndConfirm(closeVaultTx);