@picon-finance/dlmm-sdk 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -142,6 +142,17 @@ Or fetch a single position directly if you already know its address:
142
142
  const positionByAddress = await pool.getPosition(positionAddress);
143
143
  ```
144
144
 
145
+ Claim fees across many positions at once with `Position.claimAllFees()` — it skips positions with nothing pending (checked locally, no extra RPC) and batches the rest into `MAX_POSITIONS_PER_CLAIM`-sized (overridable via a third argument) instruction groups, one per transaction, sharing a single set of ATA setup/teardown instructions across the whole batch rather than repeating them per position. All positions must belong to the same pool:
146
+
147
+ ```ts
148
+ const positions = await pool.getAllPositionsByPositionMints(positionMints);
149
+ const claimTxs = await Position.claimAllFees(ownerSigner, positions);
150
+
151
+ for (const claimIxs of claimTxs) {
152
+ // build + send one transaction per entry
153
+ }
154
+ ```
155
+
145
156
  ### Events
146
157
 
147
158
  Event decoding and subscriptions are a separate, opt-in feature under the `events` namespace — independent of `DlmmProgram`/`Pool`/`Position`/`BinArray`:
@@ -33,6 +33,7 @@ export declare class Position {
33
33
  static load(pool: Pool, address: Address, config?: FetchAccountsConfig): Promise<Position>;
34
34
  static loadAll(pool: Pool, addresses: Address[], config?: FetchAccountsConfig): Promise<Position[]>;
35
35
  static refreshAll(rpc: ReturnType<typeof createSolanaRpc>, positions: Position[], config?: FetchAccountsConfig): Promise<void>;
36
+ static claimAllFees(owner: TransactionSigner, positions: Position[], positionsPerClaim?: number): Promise<Instruction[][]>;
36
37
  }
37
38
  export declare function findPositionAddress(seeds: {
38
39
  positionMint: Address;
@@ -1 +1 @@
1
- {"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../src/entities/position.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../src/entities/position.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,9 @@ import { findPositionTokenAccount, processAssociatedTokenAccountPair, } from "..
5
5
  import { getBinIndex, getBinArrayIndex, getPositionBinArrayIndices, } from "../utils/bin_location";
6
6
  import { assertRangeWithinRange, assertPositionBelongsToPool, } from "../utils/assert";
7
7
  import { isUndefined } from "../utils/type_guards";
8
- import { fetchInChunks } from "../utils/chunk";
8
+ import { chunk, fetchInChunks } from "../utils/chunk";
9
9
  import { resolveAdminConfigAddress } from "./admin_config";
10
- import { MAX_ACCOUNTS_PER_RPC_BATCH } from "../utils/constants";
10
+ import { MAX_ACCOUNTS_PER_RPC_BATCH, MAX_POSITIONS_PER_CLAIM } from "../utils/constants";
11
11
  import { BinArray, decodeAllBinArrays, createAllBinArrays, fetchAllBinArraysChunked, } from "./bin_array";
12
12
  export class Position {
13
13
  #pool;
@@ -141,21 +141,11 @@ export class Position {
141
141
  });
142
142
  return [...preInstructions, depositByWeightIx, ...postInstructions];
143
143
  }
144
- async claimFee(owner, range) {
144
+ async #buildClaimFeeInstruction(owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range) {
145
145
  const { lowerBinId, upperBinId } = range ?? this.data;
146
146
  assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
147
- const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await Promise.all([
148
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
149
- processAssociatedTokenAccountPair({
150
- owner,
151
- tokenMintX: this.#pool.tokenMintX,
152
- tokenMintY: this.#pool.tokenMintY,
153
- tokenProgramX: this.#pool.tokenProgramX,
154
- tokenProgramY: this.#pool.tokenProgramY,
155
- }),
156
- ]);
157
147
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
158
- const claimFeeIx = generated.getClaimFeeInstruction({
148
+ return generated.getClaimFeeInstruction({
159
149
  owner,
160
150
  pool: this.#pool.address,
161
151
  position: this.address,
@@ -175,6 +165,19 @@ export class Position {
175
165
  }, {
176
166
  programAddress: this.#pool.programAddress
177
167
  });
168
+ }
169
+ async claimFee(owner, range) {
170
+ const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await Promise.all([
171
+ findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
172
+ processAssociatedTokenAccountPair({
173
+ owner,
174
+ tokenMintX: this.#pool.tokenMintX,
175
+ tokenMintY: this.#pool.tokenMintY,
176
+ tokenProgramX: this.#pool.tokenProgramX,
177
+ tokenProgramY: this.#pool.tokenProgramY,
178
+ }),
179
+ ]);
180
+ const claimFeeIx = await this.#buildClaimFeeInstruction(owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range);
178
181
  return [...preInstructions, claimFeeIx, ...postInstructions];
179
182
  }
180
183
  async withdraw(owner, bpsToRemove, range) {
@@ -253,6 +256,36 @@ export class Position {
253
256
  position.#binArrays.map(binArray => binArrayByAddress.get(binArray.address)),
254
257
  ])));
255
258
  }
259
+ static async claimAllFees(owner, positions, positionsPerClaim = MAX_POSITIONS_PER_CLAIM) {
260
+ if (positions.length === 0) {
261
+ return [];
262
+ }
263
+ const pool = positions[0].#pool;
264
+ for (const position of positions) {
265
+ assertPositionBelongsToPool(position.data, pool);
266
+ }
267
+ const claimablePositions = positions.filter(position => position.getBinInfos().some(({ feeX, feeY }) => feeX > 0n || feeY > 0n));
268
+ if (claimablePositions.length === 0) {
269
+ return [];
270
+ }
271
+ const [positionTokenAccounts, { ataX, ataY, preInstructions, postInstructions }] = await Promise.all([
272
+ Promise.all(claimablePositions.map(position => findPositionTokenAccount({ owner: owner.address, positionMint: position.data.positionMint }))),
273
+ processAssociatedTokenAccountPair({
274
+ owner,
275
+ tokenMintX: pool.tokenMintX,
276
+ tokenMintY: pool.tokenMintY,
277
+ tokenProgramX: pool.tokenProgramX,
278
+ tokenProgramY: pool.tokenProgramY,
279
+ }),
280
+ ]);
281
+ const claimFeeIxs = await Promise.all(claimablePositions.map((position, i) => position.#buildClaimFeeInstruction(owner, positionTokenAccounts[i], ataX, ataY)));
282
+ const chunks = chunk(claimFeeIxs, positionsPerClaim);
283
+ return chunks.map((claimFeeIxsChunk, i) => [
284
+ ...(i === 0 ? preInstructions : []),
285
+ ...claimFeeIxsChunk,
286
+ ...(i === chunks.length - 1 ? postInstructions : []),
287
+ ]);
288
+ }
256
289
  }
257
290
  export async function findPositionAddress(seeds, config) {
258
291
  const [address] = await generated.findPositionPda(seeds, config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picon-finance/dlmm-sdk",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Typescript SDK for interacting with the Picon DLMM protocol",
5
5
  "author": "Picon Finance",
6
6
  "license": "MIT",
@@ -28,9 +28,9 @@ import {
28
28
  assertPositionBelongsToPool,
29
29
  } from "../utils/assert";
30
30
  import { isUndefined } from "../utils/type_guards";
31
- import { fetchInChunks } from "../utils/chunk";
31
+ import { chunk, fetchInChunks } from "../utils/chunk";
32
32
  import { resolveAdminConfigAddress } from "./admin_config";
33
- import { MAX_ACCOUNTS_PER_RPC_BATCH } from "../utils/constants";
33
+ import { MAX_ACCOUNTS_PER_RPC_BATCH, MAX_POSITIONS_PER_CLAIM } from "../utils/constants";
34
34
 
35
35
  import { Pool } from "./pool";
36
36
  import {
@@ -224,31 +224,18 @@ export class Position {
224
224
  return [...preInstructions, depositByWeightIx, ...postInstructions];
225
225
  }
226
226
 
227
- public async claimFee(
227
+ async #buildClaimFeeInstruction(
228
228
  owner: TransactionSigner,
229
+ positionTokenAccount: Address,
230
+ tokenOwnerAccountX: Address,
231
+ tokenOwnerAccountY: Address,
229
232
  range?: BinIdRange,
230
- ): Promise<Instruction[]> {
233
+ ): Promise<Instruction> {
231
234
  const { lowerBinId, upperBinId } = range ?? this.data;
232
235
  assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
233
236
 
234
- const [positionTokenAccount, {
235
- ataX: tokenOwnerAccountX,
236
- ataY: tokenOwnerAccountY,
237
- preInstructions,
238
- postInstructions
239
- }] = await Promise.all([
240
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
241
- processAssociatedTokenAccountPair({
242
- owner,
243
- tokenMintX: this.#pool.tokenMintX,
244
- tokenMintY: this.#pool.tokenMintY,
245
- tokenProgramX: this.#pool.tokenProgramX,
246
- tokenProgramY: this.#pool.tokenProgramY,
247
- }),
248
- ]);
249
-
250
237
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
251
- const claimFeeIx = generated.getClaimFeeInstruction({
238
+ return generated.getClaimFeeInstruction({
252
239
  owner,
253
240
  pool: this.#pool.address,
254
241
  position: this.address,
@@ -268,6 +255,31 @@ export class Position {
268
255
  }, {
269
256
  programAddress: this.#pool.programAddress
270
257
  });
258
+ }
259
+
260
+ public async claimFee(
261
+ owner: TransactionSigner,
262
+ range?: BinIdRange,
263
+ ): Promise<Instruction[]> {
264
+ const [positionTokenAccount, {
265
+ ataX: tokenOwnerAccountX,
266
+ ataY: tokenOwnerAccountY,
267
+ preInstructions,
268
+ postInstructions
269
+ }] = await Promise.all([
270
+ findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
271
+ processAssociatedTokenAccountPair({
272
+ owner,
273
+ tokenMintX: this.#pool.tokenMintX,
274
+ tokenMintY: this.#pool.tokenMintY,
275
+ tokenProgramX: this.#pool.tokenProgramX,
276
+ tokenProgramY: this.#pool.tokenProgramY,
277
+ }),
278
+ ]);
279
+
280
+ const claimFeeIx = await this.#buildClaimFeeInstruction(
281
+ owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range,
282
+ );
271
283
 
272
284
  return [...preInstructions, claimFeeIx, ...postInstructions];
273
285
  }
@@ -399,6 +411,49 @@ export class Position {
399
411
  position.#binArrays.map(binArray => binArrayByAddress.get(binArray.address)!),
400
412
  ])));
401
413
  }
414
+
415
+ public static async claimAllFees(
416
+ owner: TransactionSigner,
417
+ positions: Position[],
418
+ positionsPerClaim: number = MAX_POSITIONS_PER_CLAIM,
419
+ ): Promise<Instruction[][]> {
420
+ if (positions.length === 0) {
421
+ return [];
422
+ }
423
+
424
+ const pool = positions[0].#pool;
425
+ for (const position of positions) {
426
+ assertPositionBelongsToPool(position.data, pool);
427
+ }
428
+
429
+ const claimablePositions = positions.filter(position =>
430
+ position.getBinInfos().some(({ feeX, feeY }) => feeX > 0n || feeY > 0n));
431
+ if (claimablePositions.length === 0) {
432
+ return [];
433
+ }
434
+
435
+ const [positionTokenAccounts, { ataX, ataY, preInstructions, postInstructions }] = await Promise.all([
436
+ Promise.all(claimablePositions.map(position =>
437
+ findPositionTokenAccount({ owner: owner.address, positionMint: position.data.positionMint }))),
438
+ processAssociatedTokenAccountPair({
439
+ owner,
440
+ tokenMintX: pool.tokenMintX,
441
+ tokenMintY: pool.tokenMintY,
442
+ tokenProgramX: pool.tokenProgramX,
443
+ tokenProgramY: pool.tokenProgramY,
444
+ }),
445
+ ]);
446
+
447
+ const claimFeeIxs = await Promise.all(claimablePositions.map((position, i) =>
448
+ position.#buildClaimFeeInstruction(owner, positionTokenAccounts[i], ataX, ataY)));
449
+
450
+ const chunks = chunk(claimFeeIxs, positionsPerClaim);
451
+ return chunks.map((claimFeeIxsChunk, i) => [
452
+ ...(i === 0 ? preInstructions : []),
453
+ ...claimFeeIxsChunk,
454
+ ...(i === chunks.length - 1 ? postInstructions : []),
455
+ ]);
456
+ }
402
457
  }
403
458
 
404
459
  export async function findPositionAddress(