Skip to content

Commit

Permalink
Merge pull request #8 from MeteoraAg/bump-version
Browse files Browse the repository at this point in the history
Fix/claimable LM Rewards
  • Loading branch information
00xSam authored Jan 15, 2024
2 parents 8831acc + adea813 commit c90a0b8
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ target/*
deployment

ts-client/dist
ts-client/.env
8 changes: 7 additions & 1 deletion ts-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
"name": "@meteora-ag/dlmm-sdk-public",
"version": "1.0.1",
"description": "",
"main": "index.js",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"source": "./src/index.ts",
"types": "./dist/index.d.ts",
"files": [
"dist/**"
],
"scripts": {
"build": "tsup",
"start": "npm run build -- --watch",
Expand Down
134 changes: 109 additions & 25 deletions ts-client/src/dlmm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AccountMeta,
SYSVAR_RENT_PUBKEY,
SystemProgram,
SYSVAR_CLOCK_PUBKEY,
} from "@solana/web3.js";
import { IDL } from "./idl";
import {
Expand Down Expand Up @@ -42,7 +43,6 @@ import {
BinArray,
LiquidityParameterByWeight,
LiquidityOneSideParameter,
PositionDataXs,
BinArrayBitmapExtension,
PositionVersion,
Position,
Expand All @@ -53,7 +53,7 @@ import {
SwapFee,
LMRewards,
} from "./types";
import { AnchorProvider, BN, EventParser, Program } from "@coral-xyz/anchor";
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
import {
binIdToBinArrayIndex,
chunks,
Expand Down Expand Up @@ -103,7 +103,7 @@ export class DLMM {
public tokenX: TokenReserve,
public tokenY: TokenReserve,
private opt?: Opt
) { }
) {}

/** Static public method */

Expand Down Expand Up @@ -462,12 +462,14 @@ export class DLMM {
(pubkey) => new PublicKey(pubkey)
);

const binArraysAccInfo = await chunkedGetMultipleAccountInfos(connection, [
...binArrayPubkeyArray,
...lbPairArray,
...binArrayPubkeyArrayV2,
...lbPairArrayV2,
]);
const [clockAccInfo, ...binArraysAccInfo] =
await chunkedGetMultipleAccountInfos(connection, [
SYSVAR_CLOCK_PUBKEY,
...binArrayPubkeyArray,
...lbPairArray,
...binArrayPubkeyArrayV2,
...lbPairArrayV2,
]);

const positionBinArraysMap = new Map();
for (let i = 0; i < binArrayPubkeyArray.length; i++) {
Expand Down Expand Up @@ -510,13 +512,13 @@ export class DLMM {
let i = binArrayPubkeyArray.length + lbPairArray.length;
i <
binArrayPubkeyArray.length +
lbPairArray.length +
binArrayPubkeyArrayV2.length;
lbPairArray.length +
binArrayPubkeyArrayV2.length;
i++
) {
const binArrayPubkey =
binArrayPubkeyArrayV2[
i - (binArrayPubkeyArray.length + lbPairArray.length)
i - (binArrayPubkeyArray.length + lbPairArray.length)
];
const binArrayAccInfoBufferV2 = binArraysAccInfo[i];
if (!binArrayAccInfoBufferV2)
Expand All @@ -541,10 +543,10 @@ export class DLMM {
) {
const lbPairPubkey =
lbPairArrayV2[
i -
(binArrayPubkeyArray.length +
lbPairArray.length +
binArrayPubkeyArrayV2.length)
i -
(binArrayPubkeyArray.length +
lbPairArray.length +
binArrayPubkeyArrayV2.length)
];
const lbPairAccInfoBufferV2 = binArraysAccInfo[i];
if (!lbPairAccInfoBufferV2)
Expand Down Expand Up @@ -609,6 +611,9 @@ export class DLMM {
});
});

const onChainTimestamp = new BN(
clockAccInfo.data.readBigInt64LE(32).toString()
).toNumber();
const positionsMap: Map<
string,
{
Expand All @@ -618,7 +623,7 @@ export class DLMM {
tokenY: TokenReserve;
lbPairPositionsData: Array<{
publicKey: PublicKey;
positionData: PositionDataXs;
positionData: PositionData;
version: PositionVersion;
}>;
}
Expand Down Expand Up @@ -671,6 +676,7 @@ export class DLMM {
program,
PositionVersion.V1,
lbPairAcc,
onChainTimestamp,
account,
baseTokenDecimal,
quoteTokenDecimal,
Expand Down Expand Up @@ -744,6 +750,7 @@ export class DLMM {
program,
PositionVersion.V2,
lbPairAcc,
onChainTimestamp,
account,
baseTokenDecimal,
quoteTokenDecimal,
Expand Down Expand Up @@ -772,6 +779,69 @@ export class DLMM {
return positionsMap;
}

static async migratePosition(
connection: Connection,
positions: PublicKey[],
newPositions: PublicKey[],
walletPubkey: PublicKey,
opt?: Opt
): Promise<Transaction[]> {
const cluster = opt?.cluster || "mainnet-beta";

const provider = new AnchorProvider(
connection,
{} as any,
AnchorProvider.defaultOptions()
);
const program = new Program(IDL, LBCLMM_PROGRAM_IDS[cluster], provider);

const positionsState = await program.account.position.fetchMultiple(
positions
);

const { blockhash, lastValidBlockHeight } =
await connection.getLatestBlockhash("confirmed");
return Promise.all(
positionsState.map(async ({ lbPair, lowerBinId }, idx) => {
const position = positions[idx];
const lowerBinArrayIndex = binIdToBinArrayIndex(new BN(lowerBinId));
const upperBinArrayIndex = lowerBinArrayIndex.add(new BN(1));

const [lowerBinArrayPubKey] = deriveBinArray(
lbPair,
lowerBinArrayIndex,
program.programId
);
const [upperBinArrayPubKey] = deriveBinArray(
lbPair,
upperBinArrayIndex,
program.programId
);

const migrateTx = await program.methods
.migratePosition()
.accounts({
binArrayLower: lowerBinArrayPubKey,
binArrayUpper: upperBinArrayPubKey,
lbPair,
owner: walletPubkey,
positionV1: position,
positionV2: newPositions[idx],
program: program.programId,
rentReceiver: walletPubkey,
systemProgram: SystemProgram.programId,
})
.transaction();

return new Transaction({
blockhash,
lastValidBlockHeight,
feePayer: walletPubkey,
}).add(migrateTx);
})
);
}

/** Public methods */

public static async createLbPair(
Expand Down Expand Up @@ -1207,10 +1277,16 @@ export class DLMM {

const lbPairAndBinArrays = await chunkedGetMultipleAccountInfos(
this.program.provider.connection,
[this.pubkey, ...binArrayPubkeyArray, ...binArrayPubkeyArrayV2]
[
this.pubkey,
SYSVAR_CLOCK_PUBKEY,
...binArrayPubkeyArray,
...binArrayPubkeyArrayV2,
]
);

const [lbPairAccInfo, ...binArraysAccInfo] = lbPairAndBinArrays;
const [lbPairAccInfo, clockAccInfo, ...binArraysAccInfo] =
lbPairAndBinArrays;

const positionBinArraysMap = new Map();
for (let i = 0; i < binArrayPubkeyArray.length; i++) {
Expand Down Expand Up @@ -1250,6 +1326,9 @@ export class DLMM {
lbPairAccInfo.data
);

const onChainTimestamp = new BN(
clockAccInfo.data.readBigInt64LE(32).toString()
).toNumber();
const userPositions = await Promise.all(
positions.map(async ({ publicKey, account }) => {
const { lowerBinId, upperBinId } = account;
Expand Down Expand Up @@ -1278,6 +1357,7 @@ export class DLMM {
this.program,
PositionVersion.V1,
this.lbPair,
onChainTimestamp,
account,
this.tokenX.decimal,
this.tokenY.decimal,
Expand Down Expand Up @@ -1317,6 +1397,7 @@ export class DLMM {
this.program,
PositionVersion.V2,
this.lbPair,
onChainTimestamp,
account,
this.tokenX.decimal,
this.tokenY.decimal,
Expand Down Expand Up @@ -2145,7 +2226,8 @@ export class DLMM {
public swapQuote(
inAmount: BN,
swapForY: boolean,
allowedSlippage: BN
allowedSlippage: BN,
binArrays: BinArrayAccount[]
): SwapQuote {
// TODO: Should we use onchain clock ? Volatile fee rate is sensitive to time. Caching clock might causes the quoted fee off ...
const currentTimestamp = Date.now() / 1000;
Expand Down Expand Up @@ -2176,7 +2258,7 @@ export class DLMM {
activeId,
this.lbPair,
this.binArrayBitmapExtension?.account,
this.binArrays
binArrays
);

if (binArrayAccountToSwap == null) {
Expand Down Expand Up @@ -2618,13 +2700,12 @@ export class DLMM {
program: ClmmProgram,
positionVersion: PositionVersion,
lbPair: LbPairAccount,
onChainTimestamp: number,
position: PositionAccount,
lowerBinArray?: BinArray,
upperBinArray?: BinArray
): Promise<LMRewards> {
const lowerBinArrayIdx = binIdToBinArrayIndex(new BN(position.lowerBinId));
// Shall be using on chain clock
const currentTimestamp = Date.now() / 1000;

let rewards = [new BN(0), new BN(0)];

Expand Down Expand Up @@ -2680,7 +2761,7 @@ export class DLMM {
if (i == lbPair.activeId && !binState.liquiditySupply.isZero()) {
const currentTime = new BN(
Math.min(
currentTimestamp,
onChainTimestamp,
pairRewardInfo.rewardDurationEnd.toNumber()
)
);
Expand All @@ -2691,6 +2772,7 @@ export class DLMM {
: binState.liquiditySupply.shrn(64);
const rewardPerTokenStoredDelta = pairRewardInfo.rewardRate
.mul(delta)
.div(new BN(15))
.div(liquiditySupply);
rewardPerTokenStored = rewardPerTokenStored.add(
rewardPerTokenStoredDelta
Expand Down Expand Up @@ -2799,6 +2881,7 @@ export class DLMM {
program: ClmmProgram,
version: PositionVersion,
lbPair: LbPairAccount,
onChainTimestamp: number,
positionAccount: PositionAccount,
baseTokenDecimal: number,
quoteTokenDecimal: number,
Expand Down Expand Up @@ -2878,6 +2961,7 @@ export class DLMM {
program,
version,
lbPair,
onChainTimestamp,
positionAccount,
lowerBinArray,
upperBinArray
Expand Down Expand Up @@ -3164,7 +3248,7 @@ export class DLMM {
if (elapsed < sParameter.decayPeriod) {
const decayedVolatilityReference = Math.floor(
(vParameter.volatilityAccumulator * sParameter.reductionFactor) /
BASIS_POINT_MAX
BASIS_POINT_MAX
);
vParameter.volatilityReference = decayedVolatilityReference;
} else {
Expand Down
7 changes: 1 addition & 6 deletions ts-client/src/dlmm/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export type LiquidityOneSideParameter =

export interface Position {
publicKey: PublicKey;
positionData: PositionDataXs;
positionData: PositionData;
version: PositionVersion;
}

Expand Down Expand Up @@ -192,11 +192,6 @@ export interface PositionData {
rewardTwo: BN;
}

export type PositionDataXs = Omit<
PositionData,
"feeX" | "feeY" | "rewardOne" | "rewardTwo"
>;

export interface SwapParams {
/**
* mint of in token
Expand Down
12 changes: 8 additions & 4 deletions ts-client/src/test/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,9 @@ describe("SDK test", () => {

btcInAmount = btcAmountToSwapHalfUsdcOfActiveBin;

const binArrays = await lbClmm.getBinArrays();
const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =
lbClmm.swapQuote(btcInAmount, true, new BN(0));
lbClmm.swapQuote(btcInAmount, true, new BN(0), binArrays);
expect(outAmount.toString()).not.toEqual("0");
expect(fee.toString()).not.toEqual("0");
// Swap within active bin has no price impact
Expand Down Expand Up @@ -544,8 +545,9 @@ describe("SDK test", () => {
);

usdcInAmount = usdcAmountToSwapHalfBtcOfActiveBin;
const binArrays = await lbClmm.getBinArrays();
const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =
lbClmm.swapQuote(usdcInAmount, false, new BN(0));
lbClmm.swapQuote(usdcInAmount, false, new BN(0), binArrays);
expect(outAmount.toString()).not.toEqual("0");
expect(fee.toString()).not.toEqual("0");
// Swap within active bin has no price impact
Expand Down Expand Up @@ -631,8 +633,9 @@ describe("SDK test", () => {

btcInAmount = new BN(btcAmountToCrossBin + 1);

const binArrays = await lbClmm.getBinArrays();
const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =
lbClmm.swapQuote(btcInAmount, true, new BN(0));
lbClmm.swapQuote(btcInAmount, true, new BN(0), binArrays);
expect(outAmount.toString()).not.toEqual("0");
expect(fee.toString()).not.toEqual("0");
// Swap with crossing bins has price impact
Expand Down Expand Up @@ -703,8 +706,9 @@ describe("SDK test", () => {
Number.parseFloat(afterActiveBin.price);
usdcInAmount = new BN(usdcAmountToCrossBin + 1);

const binArrays = await lbClmm.getBinArrays();
const { fee, outAmount, priceImpact, protocolFee, binArraysPubkey } =
lbClmm.swapQuote(usdcInAmount, false, new BN(0));
lbClmm.swapQuote(usdcInAmount, false, new BN(0), binArrays);
expect(outAmount.toString()).not.toEqual("0");
expect(fee.toString()).not.toEqual("0");
// Swap with crossing bins has price impact
Expand Down

0 comments on commit c90a0b8

Please sign in to comment.