From ad7e6e4ccc8de7702e7135d21ccd04c54e1bd347 Mon Sep 17 00:00:00 2001 From: McSam Date: Sat, 13 Jan 2024 08:27:02 +0800 Subject: [PATCH 1/5] bump: version --- ts-client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts-client/package.json b/ts-client/package.json index 3ca2d9cf..6bb063eb 100644 --- a/ts-client/package.json +++ b/ts-client/package.json @@ -1,6 +1,6 @@ { "name": "@meteora-ag/dlmm-sdk-public", - "version": "1.0.0", + "version": "1.0.1", "description": "", "main": "index.js", "scripts": { From 13b6e82ae0a4ebe10955379bd58d3b32b3391b99 Mon Sep 17 00:00:00 2001 From: McSam Date: Sat, 13 Jan 2024 08:44:46 +0800 Subject: [PATCH 2/5] add gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fdb4ada6..be84f74f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ target/* deployment ts-client/dist +ts-client/.env From d27828e69e0a56c4cdfb304f8c87af10dfe028bc Mon Sep 17 00:00:00 2001 From: McSam Date: Sun, 14 Jan 2024 13:21:34 +0800 Subject: [PATCH 3/5] fix: getClaimableRewards --- ts-client/src/dlmm/index.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ts-client/src/dlmm/index.ts b/ts-client/src/dlmm/index.ts index 37d6e716..a64d25fa 100644 --- a/ts-client/src/dlmm/index.ts +++ b/ts-client/src/dlmm/index.ts @@ -103,7 +103,7 @@ export class DLMM { public tokenX: TokenReserve, public tokenY: TokenReserve, private opt?: Opt - ) { } + ) {} /** Static public method */ @@ -510,13 +510,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) @@ -541,10 +541,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) @@ -2691,6 +2691,7 @@ export class DLMM { : binState.liquiditySupply.shrn(64); const rewardPerTokenStoredDelta = pairRewardInfo.rewardRate .mul(delta) + .div(new BN(15)) .div(liquiditySupply); rewardPerTokenStored = rewardPerTokenStored.add( rewardPerTokenStoredDelta @@ -3164,7 +3165,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 { From 21bb595c4f9576c0edfd2598a13e9b7a2cff1796 Mon Sep 17 00:00:00 2001 From: McSam Date: Sun, 14 Jan 2024 16:26:18 +0800 Subject: [PATCH 4/5] update: get claimable rewards to minimum --- ts-client/package.json | 8 ++- ts-client/src/dlmm/index.ts | 115 +++++++++++++++++++++++++----- ts-client/src/dlmm/types/index.ts | 7 +- 3 files changed, 107 insertions(+), 23 deletions(-) diff --git a/ts-client/package.json b/ts-client/package.json index 6bb063eb..c24a869c 100644 --- a/ts-client/package.json +++ b/ts-client/package.json @@ -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", diff --git a/ts-client/src/dlmm/index.ts b/ts-client/src/dlmm/index.ts index a64d25fa..f1db2987 100644 --- a/ts-client/src/dlmm/index.ts +++ b/ts-client/src/dlmm/index.ts @@ -7,6 +7,7 @@ import { AccountMeta, SYSVAR_RENT_PUBKEY, SystemProgram, + SYSVAR_CLOCK_PUBKEY, } from "@solana/web3.js"; import { IDL } from "./idl"; import { @@ -42,7 +43,6 @@ import { BinArray, LiquidityParameterByWeight, LiquidityOneSideParameter, - PositionDataXs, BinArrayBitmapExtension, PositionVersion, Position, @@ -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, @@ -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++) { @@ -609,6 +611,9 @@ export class DLMM { }); }); + const onChainTimestamp = new BN( + clockAccInfo.data.readBigInt64LE(32).toString() + ).toNumber(); const positionsMap: Map< string, { @@ -618,7 +623,7 @@ export class DLMM { tokenY: TokenReserve; lbPairPositionsData: Array<{ publicKey: PublicKey; - positionData: PositionDataXs; + positionData: PositionData; version: PositionVersion; }>; } @@ -671,6 +676,7 @@ export class DLMM { program, PositionVersion.V1, lbPairAcc, + onChainTimestamp, account, baseTokenDecimal, quoteTokenDecimal, @@ -744,6 +750,7 @@ export class DLMM { program, PositionVersion.V2, lbPairAcc, + onChainTimestamp, account, baseTokenDecimal, quoteTokenDecimal, @@ -772,6 +779,69 @@ export class DLMM { return positionsMap; } + static async migratePosition( + connection: Connection, + positions: PublicKey[], + newPositions: PublicKey[], + walletPubkey: PublicKey, + opt?: Opt + ): Promise { + 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( @@ -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++) { @@ -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; @@ -1278,6 +1357,7 @@ export class DLMM { this.program, PositionVersion.V1, this.lbPair, + onChainTimestamp, account, this.tokenX.decimal, this.tokenY.decimal, @@ -1317,6 +1397,7 @@ export class DLMM { this.program, PositionVersion.V2, this.lbPair, + onChainTimestamp, account, this.tokenX.decimal, this.tokenY.decimal, @@ -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; @@ -2176,7 +2258,7 @@ export class DLMM { activeId, this.lbPair, this.binArrayBitmapExtension?.account, - this.binArrays + binArrays ); if (binArrayAccountToSwap == null) { @@ -2618,13 +2700,12 @@ export class DLMM { program: ClmmProgram, positionVersion: PositionVersion, lbPair: LbPairAccount, + onChainTimestamp: number, position: PositionAccount, lowerBinArray?: BinArray, upperBinArray?: BinArray ): Promise { 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)]; @@ -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() ) ); @@ -2800,6 +2881,7 @@ export class DLMM { program: ClmmProgram, version: PositionVersion, lbPair: LbPairAccount, + onChainTimestamp: number, positionAccount: PositionAccount, baseTokenDecimal: number, quoteTokenDecimal: number, @@ -2879,6 +2961,7 @@ export class DLMM { program, version, lbPair, + onChainTimestamp, positionAccount, lowerBinArray, upperBinArray diff --git a/ts-client/src/dlmm/types/index.ts b/ts-client/src/dlmm/types/index.ts index 3e1470df..725862a2 100644 --- a/ts-client/src/dlmm/types/index.ts +++ b/ts-client/src/dlmm/types/index.ts @@ -62,7 +62,7 @@ export type LiquidityOneSideParameter = export interface Position { publicKey: PublicKey; - positionData: PositionDataXs; + positionData: PositionData; version: PositionVersion; } @@ -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 From adea81312621a38f877a9da6837e173cbfe70744 Mon Sep 17 00:00:00 2001 From: McSam Date: Mon, 15 Jan 2024 10:19:39 +0800 Subject: [PATCH 5/5] fix: test case --- ts-client/src/test/sdk.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ts-client/src/test/sdk.test.ts b/ts-client/src/test/sdk.test.ts index 75ca2ebf..7778f190 100644 --- a/ts-client/src/test/sdk.test.ts +++ b/ts-client/src/test/sdk.test.ts @@ -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 @@ -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 @@ -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 @@ -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