@picon-finance/dlmm-sdk 1.16.4 → 1.17.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
@@ -98,7 +98,7 @@ const depositIxs = await position.depositByWeight(ownerSigner, {
98
98
 
99
99
  // Later: claim fees, withdraw (partially or fully, by bps), close.
100
100
  const claimFeeIxs = await position.claimFee(ownerSigner);
101
- const withdrawIxs = await position.withdraw(ownerSigner, 5_000); // bps, out of 10_000 = 100%
101
+ const withdrawIxs = await position.withdraw(ownerSigner, { bpsToRemove: 5_000 }); // bps, out of 10_000 = 100%
102
102
  const closeIx = await position.close(ownerSigner);
103
103
  ```
104
104
 
@@ -1 +1 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ import { resolveAdminConfigAddress } from "./admin_config";
7
7
  import { processAssociatedTokenAccountPair } from "../utils/ata";
8
8
  import { getBinArrayIndex, getBinArrayIndexSequence, generateBinArrayIndicesForSwap, generateBinArrayIndicesForSync, } from "../utils/bin_location";
9
9
  import { resolveTransferFee } from "../utils/transfer_fee";
10
- import { resolveTransferHookProgram, resolveTransferHookExtraAccounts, toRemainingAccountMeta, } from "../utils/transfer_hook";
10
+ import { appendRemainingAccounts, buildTransferHookScheme, resolveTransferHookProgram, resolveTransferHookExtraAccounts, } from "../utils/transfer_hook";
11
11
  import { MAX_BIN_ARRAYS_PER_TRAVERSAL } from "../utils/constants";
12
12
  import { Position, openPosition, closePosition, findPositionAddress, findAllPositionAddresses, } from "./position";
13
13
  import { BinArray, findAllBinArrayAddresses } from "./bin_array";
@@ -147,25 +147,21 @@ export class Pool {
147
147
  this.resolveTransferHookAccountsX(xTransferAccounts),
148
148
  this.resolveTransferHookAccountsY(yTransferAccounts),
149
149
  ]);
150
+ const hookScheme = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
150
151
  const groups = [
151
152
  { kind: generated.AccountKind.BinArray, count: binArrayAddresses.length },
153
+ ...hookScheme.groups,
154
+ ];
155
+ const remainingAccounts = [
156
+ ...binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE })),
157
+ ...hookScheme.remainingAccounts,
152
158
  ];
153
- const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
154
- if (transferHookXAccounts.length > 0) {
155
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
156
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
157
- }
158
- if (transferHookYAccounts.length > 0) {
159
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
160
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
161
- }
162
159
  const swapIx = buildSwapIx({
163
160
  tokenUserAccountX,
164
161
  tokenUserAccountY,
165
162
  remainingAccountsScheme: { groups },
166
163
  });
167
- const swapIxWithBinArrays = { ...swapIx, accounts: [...(swapIx.accounts ?? []), ...remainingAccounts] };
168
- return [...preInstructions, swapIxWithBinArrays, ...postInstructions];
164
+ return [...preInstructions, appendRemainingAccounts(swapIx, remainingAccounts), ...postInstructions];
169
165
  }
170
166
  // Public so Position (which only holds a reference to this Pool, not its private mint data)
171
167
  // can resolve hook accounts for its own deposit/withdraw/claimFee instructions without ever
@@ -283,16 +279,7 @@ export class Pool {
283
279
  source: this.tokenVaultY, mint: this.tokenMintY, destination: tokenAdminAccountY, owner: this.address,
284
280
  }),
285
281
  ]);
286
- const groups = [];
287
- const remainingAccounts = [];
288
- if (transferHookXAccounts.length > 0) {
289
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
290
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
291
- }
292
- if (transferHookYAccounts.length > 0) {
293
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
294
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
295
- }
282
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
296
283
  const claimProtocolFeeIx = await generated.getClaimProtocolFeeInstructionAsync({
297
284
  authority,
298
285
  pool: this.address,
@@ -307,11 +294,7 @@ export class Pool {
307
294
  tokenProgramX: this.tokenProgramX,
308
295
  tokenProgramY: this.tokenProgramY,
309
296
  }, { programAddress: this.#programAddress });
310
- const claimProtocolFeeIxWithHookAccounts = {
311
- ...claimProtocolFeeIx,
312
- accounts: [...claimProtocolFeeIx.accounts, ...remainingAccounts],
313
- };
314
- return [...preInstructions, claimProtocolFeeIxWithHookAccounts, ...postInstructions];
297
+ return [...preInstructions, appendRemainingAccounts(claimProtocolFeeIx, remainingAccounts), ...postInstructions];
315
298
  }
316
299
  static async load(rpc, address, programAddress, config) {
317
300
  const pool = await generated.fetchPool(rpc, address, config);
@@ -27,8 +27,13 @@ export declare class Position {
27
27
  maxActiveBinSlippage: number;
28
28
  distributionMode: generated.DistributionMode;
29
29
  }): Promise<Instruction[]>;
30
- claimFee(owner: TransactionSigner, range?: BinIdRange): Promise<Instruction[]>;
31
- withdraw(owner: TransactionSigner, bpsToRemove: number, range?: BinIdRange): Promise<Instruction[]>;
30
+ claimFee(owner: TransactionSigner, { range }?: {
31
+ range?: BinIdRange;
32
+ }): Promise<Instruction[]>;
33
+ withdraw(owner: TransactionSigner, { bpsToRemove, range }: {
34
+ bpsToRemove: number;
35
+ range?: BinIdRange;
36
+ }): Promise<Instruction[]>;
32
37
  close(owner: TransactionSigner): Promise<Instruction>;
33
38
  static load(pool: Pool, address: Address, config?: FetchAccountsConfig): Promise<Position>;
34
39
  static loadAll(pool: Pool, addresses: Address[], config?: FetchAccountsConfig): Promise<Position[]>;
@@ -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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"}
@@ -2,7 +2,7 @@ import { decodeAccount, assertAccountExists, fetchEncodedAccounts, } from "@sola
2
2
  import { generated } from "..";
3
3
  import { getAmountAfterTransferFee } from "../quote";
4
4
  import { findPositionTokenAccount, processAssociatedTokenAccountPair, } from "../utils/ata";
5
- import { toRemainingAccountMeta } from "../utils/transfer_hook";
5
+ import { appendRemainingAccounts, buildTransferHookScheme, } from "../utils/transfer_hook";
6
6
  import { getBinIndex, getBinArrayIndex, getPositionBinArrayIndices, } from "../utils/bin_location";
7
7
  import { assertRangeWithinRange, assertPositionBelongsToPool, } from "../utils/assert";
8
8
  import { isUndefined } from "../utils/type_guards";
@@ -97,12 +97,14 @@ export class Position {
97
97
  }
98
98
  const [position, binArrays] = arg;
99
99
  this.#account = position;
100
- this.#binArrays.forEach((b, i) => b.refresh(binArrays[i]));
100
+ await Promise.all(this.#binArrays.map((b, i) => b.refresh(binArrays[i])));
101
101
  }
102
- async depositByWeight(owner, { amountX, amountY, lowerBinId, binWeights, maxActiveBinSlippage, distributionMode, }) {
103
- const upperBinId = lowerBinId + binWeights.length - 1;
104
- assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
105
- const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await Promise.all([
102
+ // Shared by depositByWeight/claimFee/withdraw — each needs the owner's position-NFT token
103
+ // account plus its X/Y ATAs (creating either that don't exist yet, funding wSOL if native).
104
+ // amounts is only relevant for a deposit (it decides how much wSOL to wrap); omitted for
105
+ // claim/withdraw, which only ever receive tokens.
106
+ async #prepareOwnerAccounts(owner, amounts) {
107
+ return await Promise.all([
106
108
  findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
107
109
  processAssociatedTokenAccountPair({
108
110
  owner,
@@ -110,10 +112,15 @@ export class Position {
110
112
  tokenMintY: this.#pool.tokenMintY,
111
113
  tokenProgramX: this.#pool.tokenProgramX,
112
114
  tokenProgramY: this.#pool.tokenProgramY,
113
- amountX,
114
- amountY,
115
+ amountX: amounts?.amountX,
116
+ amountY: amounts?.amountY,
115
117
  }),
116
118
  ]);
119
+ }
120
+ async depositByWeight(owner, { amountX, amountY, lowerBinId, binWeights, maxActiveBinSlippage, distributionMode, }) {
121
+ const upperBinId = lowerBinId + binWeights.length - 1;
122
+ assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
123
+ const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await this.#prepareOwnerAccounts(owner, { amountX, amountY });
117
124
  // Both legs move owner -> vault (deposit), signed by owner itself.
118
125
  const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
119
126
  this.#pool.resolveTransferHookAccountsX({
@@ -123,16 +130,7 @@ export class Position {
123
130
  source: tokenOwnerAccountY, mint: this.#pool.tokenMintY, destination: this.#pool.tokenVaultY, owner: owner.address,
124
131
  }),
125
132
  ]);
126
- const groups = [];
127
- const remainingAccounts = [];
128
- if (transferHookXAccounts.length > 0) {
129
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
130
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
131
- }
132
- if (transferHookYAccounts.length > 0) {
133
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
134
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
135
- }
133
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
136
134
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
137
135
  const depositByWeightIx = generated.getDepositByWeightInstruction({
138
136
  owner,
@@ -160,11 +158,7 @@ export class Position {
160
158
  }, {
161
159
  programAddress: this.#pool.programAddress
162
160
  });
163
- const depositByWeightIxWithHookAccounts = {
164
- ...depositByWeightIx,
165
- accounts: [...depositByWeightIx.accounts, ...remainingAccounts],
166
- };
167
- return [...preInstructions, depositByWeightIxWithHookAccounts, ...postInstructions];
161
+ return [...preInstructions, appendRemainingAccounts(depositByWeightIx, remainingAccounts), ...postInstructions];
168
162
  }
169
163
  async #buildClaimFeeInstruction(owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range) {
170
164
  const { lowerBinId, upperBinId } = range ?? this.data;
@@ -178,16 +172,7 @@ export class Position {
178
172
  source: this.#pool.tokenVaultY, mint: this.#pool.tokenMintY, destination: tokenOwnerAccountY, owner: this.#pool.address,
179
173
  }),
180
174
  ]);
181
- const groups = [];
182
- const remainingAccounts = [];
183
- if (transferHookXAccounts.length > 0) {
184
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
185
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
186
- }
187
- if (transferHookYAccounts.length > 0) {
188
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
189
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
190
- }
175
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
191
176
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
192
177
  const claimFeeIx = generated.getClaimFeeInstruction({
193
178
  owner,
@@ -210,35 +195,17 @@ export class Position {
210
195
  }, {
211
196
  programAddress: this.#pool.programAddress
212
197
  });
213
- return { ...claimFeeIx, accounts: [...claimFeeIx.accounts, ...remainingAccounts] };
198
+ return appendRemainingAccounts(claimFeeIx, remainingAccounts);
214
199
  }
215
- async claimFee(owner, range) {
216
- const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await Promise.all([
217
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
218
- processAssociatedTokenAccountPair({
219
- owner,
220
- tokenMintX: this.#pool.tokenMintX,
221
- tokenMintY: this.#pool.tokenMintY,
222
- tokenProgramX: this.#pool.tokenProgramX,
223
- tokenProgramY: this.#pool.tokenProgramY,
224
- }),
225
- ]);
200
+ async claimFee(owner, { range } = {}) {
201
+ const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await this.#prepareOwnerAccounts(owner);
226
202
  const claimFeeIx = await this.#buildClaimFeeInstruction(owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range);
227
203
  return [...preInstructions, claimFeeIx, ...postInstructions];
228
204
  }
229
- async withdraw(owner, bpsToRemove, range) {
205
+ async withdraw(owner, { bpsToRemove, range }) {
230
206
  const { lowerBinId, upperBinId } = range ?? this.data;
231
207
  assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
232
- const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await Promise.all([
233
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
234
- processAssociatedTokenAccountPair({
235
- owner,
236
- tokenMintX: this.#pool.tokenMintX,
237
- tokenMintY: this.#pool.tokenMintY,
238
- tokenProgramX: this.#pool.tokenProgramX,
239
- tokenProgramY: this.#pool.tokenProgramY,
240
- }),
241
- ]);
208
+ const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await this.#prepareOwnerAccounts(owner);
242
209
  // Both legs move vault -> owner (withdraw), signed by the pool PDA.
243
210
  const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
244
211
  this.#pool.resolveTransferHookAccountsX({
@@ -248,16 +215,7 @@ export class Position {
248
215
  source: this.#pool.tokenVaultY, mint: this.#pool.tokenMintY, destination: tokenOwnerAccountY, owner: this.#pool.address,
249
216
  }),
250
217
  ]);
251
- const groups = [];
252
- const remainingAccounts = [];
253
- if (transferHookXAccounts.length > 0) {
254
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
255
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
256
- }
257
- if (transferHookYAccounts.length > 0) {
258
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
259
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
260
- }
218
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
261
219
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
262
220
  const withdrawIx = generated.getWithdrawInstruction({
263
221
  owner,
@@ -281,11 +239,7 @@ export class Position {
281
239
  }, {
282
240
  programAddress: this.#pool.programAddress
283
241
  });
284
- const withdrawIxWithHookAccounts = {
285
- ...withdrawIx,
286
- accounts: [...withdrawIx.accounts, ...remainingAccounts],
287
- };
288
- return [...preInstructions, withdrawIxWithHookAccounts, ...postInstructions];
242
+ return [...preInstructions, appendRemainingAccounts(withdrawIx, remainingAccounts), ...postInstructions];
289
243
  }
290
244
  async close(owner) {
291
245
  return await closePosition({ owner, positionMint: this.data.positionMint, position: this.address }, { programAddress: this.#pool.programAddress });
@@ -9,16 +9,6 @@ export declare function findPositionTokenAccount({ owner, positionMint, }: {
9
9
  owner: Address;
10
10
  positionMint: Address;
11
11
  }): Promise<Address>;
12
- export declare function findPoolTokenVaults({ pool, tokenMintX, tokenMintY, tokenProgramX, tokenProgramY, }: {
13
- pool: Address;
14
- tokenMintX: Address;
15
- tokenMintY: Address;
16
- tokenProgramX: Address;
17
- tokenProgramY: Address;
18
- }): Promise<{
19
- tokenVaultX: Address;
20
- tokenVaultY: Address;
21
- }>;
22
12
  interface ProcessAssociatedTokenAccountParams {
23
13
  owner: TransactionSigner;
24
14
  mint: Address;
@@ -1 +1 @@
1
- {"version":3,"file":"ata.d.ts","sourceRoot":"","sources":["../../src/utils/ata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAerB,eAAO,MAAM,mBAAmB,EAAoD,OAAO,CAAC;AAE5F,wBAAsB,oCAAoC,CAAC,MAAM,EAAE;IACjE,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;CACvB,4BAIA;AAID,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,YAAY,GACb,EAAE;IACD,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnB;AAID,wBAAsB,mBAAmB,CAAC,EACxC,IAAI,EACJ,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,GACd,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAM1D;AAED,UAAU,mCAAmC;IAC3C,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,mCAAmC;IAC3C,GAAG,EAAE,OAAO,CAAC;IACb,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAMvI;AAKD,wBAAsB,iCAAiC,CAAC,EACtD,KAAK,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,OAAO,EACP,OAAO,GACR,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IACV,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC,CAAC,CAWD"}
1
+ {"version":3,"file":"ata.d.ts","sourceRoot":"","sources":["../../src/utils/ata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAerB,eAAO,MAAM,mBAAmB,EAAoD,OAAO,CAAC;AAE5F,wBAAsB,oCAAoC,CAAC,MAAM,EAAE;IACjE,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;CACvB,4BAIA;AAID,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,YAAY,GACb,EAAE;IACD,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnB;AAED,UAAU,mCAAmC;IAC3C,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,mCAAmC;IAC3C,GAAG,EAAE,OAAO,CAAC;IACb,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAMvI;AAKD,wBAAsB,iCAAiC,CAAC,EACtD,KAAK,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,OAAO,EACP,OAAO,GACR,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IACV,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,WAAW,EAAE,CAAC;IAC/B,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC,CAAC,CAWD"}
package/dist/utils/ata.js CHANGED
@@ -12,15 +12,6 @@ export async function findAssociatedTokenPdaByTokenProgram(params) {
12
12
  export function findPositionTokenAccount({ owner, positionMint, }) {
13
13
  return findAssociatedTokenPdaByTokenProgram({ owner, mint: positionMint, tokenProgram: TOKEN_2022_PROGRAM_ADDRESS });
14
14
  }
15
- // A pool's X/Y vaults — shared by every instruction that moves tokens through a pool
16
- // (withdraw, claim_fee, claim_multiple_fees, claim_protocol_fee, deposit_by_weight, swap).
17
- export async function findPoolTokenVaults({ pool, tokenMintX, tokenMintY, tokenProgramX, tokenProgramY, }) {
18
- const [tokenVaultX, tokenVaultY] = await Promise.all([
19
- findAssociatedTokenPdaByTokenProgram({ owner: pool, mint: tokenMintX, tokenProgram: tokenProgramX }),
20
- findAssociatedTokenPdaByTokenProgram({ owner: pool, mint: tokenMintY, tokenProgram: tokenProgramY }),
21
- ]);
22
- return { tokenVaultX, tokenVaultY };
23
- }
24
15
  export function processAssociatedTokenAccount(params) {
25
16
  if (params.mint === NATIVE_MINT_ADDRESS) {
26
17
  return processWsolAssociatedTokenAccount(params);
@@ -1,5 +1,6 @@
1
1
  import { AccountRole, createSolanaRpc, type Address } from "@solana/kit";
2
2
  import type { Mint } from "@solana-program/token-2022";
3
+ import * as generated from "../generated";
3
4
  export declare function resolveTransferHookProgram(mint: Mint): Address | undefined;
4
5
  export declare function getExtraAccountMetaListAddress(mint: Address, hookProgram: Address): Promise<Address>;
5
6
  export type ExtraAccount = {
@@ -18,4 +19,15 @@ export declare function toRemainingAccountMeta({ address, isSigner, isWritable }
18
19
  address: Address;
19
20
  role: AccountRole;
20
21
  };
22
+ export type RemainingAccountMeta = {
23
+ address: Address;
24
+ role: AccountRole;
25
+ };
26
+ export declare function buildTransferHookScheme(transferHookXAccounts: ExtraAccount[], transferHookYAccounts: ExtraAccount[]): {
27
+ groups: generated.AccountGroup[];
28
+ remainingAccounts: RemainingAccountMeta[];
29
+ };
30
+ export declare function appendRemainingAccounts<TIx extends {
31
+ accounts?: readonly unknown[];
32
+ }>(instruction: TIx, remainingAccounts: RemainingAccountMeta[]): TIx;
21
33
  //# sourceMappingURL=transfer_hook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transfer_hook.d.ts","sourceRoot":"","sources":["../../src/utils/transfer_hook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAIX,eAAe,EAEf,KAAK,OAAO,EACb,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,IAAI,EAAa,MAAM,4BAA4B,CAAC;AA8BlE,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAQ1E;AAKD,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC,OAAO,CAAC,CAQlB;AA4ED,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AA+CF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAWF,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACvC,WAAW,EAAE,OAAO,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,eAAe,GAAE,UAA6B,GAC7C,OAAO,CAAC,YAAY,EAAE,CAAC,CAqEzB;AAGD,wBAAgB,sBAAsB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,YAAY;;;EAKrF"}
1
+ {"version":3,"file":"transfer_hook.d.ts","sourceRoot":"","sources":["../../src/utils/transfer_hook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAIX,eAAe,EAEf,KAAK,OAAO,EACb,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,IAAI,EAAa,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,SAAS,MAAM,cAAc,CAAC;AA8B1C,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAQ1E;AAKD,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC,OAAO,CAAC,CAQlB;AA4ED,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AA+CF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAWF,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACvC,WAAW,EAAE,OAAO,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,eAAe,GAAE,UAA6B,GAC7C,OAAO,CAAC,YAAY,EAAE,CAAC,CAqEzB;AAGD,wBAAgB,sBAAsB,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,YAAY;;;EAKrF;AAED,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAO3E,wBAAgB,uBAAuB,CACrC,qBAAqB,EAAE,YAAY,EAAE,EACrC,qBAAqB,EAAE,YAAY,EAAE,GACpC;IAAE,MAAM,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC;IAAC,iBAAiB,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAcjF;AAKD,wBAAgB,uBAAuB,CAAC,GAAG,SAAS;IAAE,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,EACnF,WAAW,EAAE,GAAG,EAChB,iBAAiB,EAAE,oBAAoB,EAAE,GACxC,GAAG,CAEL"}
@@ -1,5 +1,6 @@
1
1
  import { AccountRole, getAddressEncoder, getAddressDecoder, getProgramDerivedAddress, unwrapOption, } from "@solana/kit";
2
2
  import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
3
+ import * as generated from "../generated";
3
4
  const EXTRA_ACCOUNT_METAS_SEED = "extra-account-metas";
4
5
  // spl-tlv-account-resolution's on-chain byte layout (verified against the actual Rust crate
5
6
  // source, spl-tlv-account-resolution 0.4.0's account.rs/state.rs/seeds.rs — not guessed):
@@ -198,3 +199,27 @@ export function toRemainingAccountMeta({ address, isSigner, isWritable }) {
198
199
  : (isWritable ? AccountRole.WRITABLE : AccountRole.READONLY);
199
200
  return { address, role };
200
201
  }
202
+ // Builds the TransferHookX/TransferHookY groups + their remaining-account metas from a resolved
203
+ // pair of hook accounts — one group per side, omitted entirely when that side has no active hook
204
+ // (mirrors the on-chain program's own RemainingAccountsScheme, which only expects a group to be
205
+ // present when the corresponding mint actually carries a hook). Callers that also need a group
206
+ // ahead of these (e.g. swap's BinArray group) prepend their own groups/accounts to the result.
207
+ export function buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts) {
208
+ const groups = [];
209
+ const remainingAccounts = [];
210
+ if (transferHookXAccounts.length > 0) {
211
+ groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
212
+ remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
213
+ }
214
+ if (transferHookYAccounts.length > 0) {
215
+ groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
216
+ remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
217
+ }
218
+ return { groups, remainingAccounts };
219
+ }
220
+ // Appends resolved remaining-account metas (transfer hook accounts, bin arrays, ...) onto an
221
+ // already-built instruction — the one-line splice every instruction builder in entities/ needs
222
+ // after computing its own RemainingAccountsScheme.
223
+ export function appendRemainingAccounts(instruction, remainingAccounts) {
224
+ return { ...instruction, accounts: [...(instruction.accounts ?? []), ...remainingAccounts] };
225
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picon-finance/dlmm-sdk",
3
- "version": "1.16.4",
3
+ "version": "1.17.0",
4
4
  "description": "Typescript SDK for interacting with the Picon DLMM protocol",
5
5
  "author": "Picon Finance",
6
6
  "license": "MIT",
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/bun": "latest",
55
- "@codama/nodes-from-anchor": "^1.5.2",
56
- "@codama/renderers-js": "^2.3.0",
57
- "codama": "^1.9.0"
55
+ "@codama/nodes-from-anchor": "^1.5.3",
56
+ "@codama/renderers-js": "^2.3.1",
57
+ "codama": "^1.10.0"
58
58
  }
59
59
  }
@@ -34,9 +34,10 @@ import {
34
34
  } from "../utils/bin_location";
35
35
  import { resolveTransferFee } from "../utils/transfer_fee";
36
36
  import {
37
+ appendRemainingAccounts,
38
+ buildTransferHookScheme,
37
39
  resolveTransferHookProgram,
38
40
  resolveTransferHookExtraAccounts,
39
- toRemainingAccountMeta,
40
41
  type ExtraAccount,
41
42
  type TransferAccounts as TransferHookAccounts,
42
43
  } from "../utils/transfer_hook";
@@ -311,28 +312,23 @@ export class Pool {
311
312
  this.resolveTransferHookAccountsY(yTransferAccounts),
312
313
  ]);
313
314
 
315
+ const hookScheme = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
314
316
  const groups: generated.AccountGroup[] = [
315
317
  { kind: generated.AccountKind.BinArray, count: binArrayAddresses.length },
318
+ ...hookScheme.groups,
319
+ ];
320
+ const remainingAccounts = [
321
+ ...binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE })),
322
+ ...hookScheme.remainingAccounts,
316
323
  ];
317
- const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
318
-
319
- if (transferHookXAccounts.length > 0) {
320
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
321
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
322
- }
323
- if (transferHookYAccounts.length > 0) {
324
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
325
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
326
- }
327
324
 
328
325
  const swapIx = buildSwapIx({
329
326
  tokenUserAccountX,
330
327
  tokenUserAccountY,
331
328
  remainingAccountsScheme: { groups },
332
329
  });
333
- const swapIxWithBinArrays = { ...swapIx, accounts: [...(swapIx.accounts ?? []), ...remainingAccounts] };
334
330
 
335
- return [...preInstructions, swapIxWithBinArrays, ...postInstructions];
331
+ return [...preInstructions, appendRemainingAccounts(swapIx, remainingAccounts), ...postInstructions];
336
332
  }
337
333
 
338
334
  // Public so Position (which only holds a reference to this Pool, not its private mint data)
@@ -548,17 +544,7 @@ export class Pool {
548
544
  }),
549
545
  ]);
550
546
 
551
- const groups: generated.AccountGroup[] = [];
552
- const remainingAccounts: { address: Address, role: AccountRole }[] = [];
553
-
554
- if (transferHookXAccounts.length > 0) {
555
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
556
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
557
- }
558
- if (transferHookYAccounts.length > 0) {
559
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
560
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
561
- }
547
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
562
548
 
563
549
  const claimProtocolFeeIx = await generated.getClaimProtocolFeeInstructionAsync({
564
550
  authority,
@@ -575,12 +561,7 @@ export class Pool {
575
561
  tokenProgramY: this.tokenProgramY,
576
562
  }, { programAddress: this.#programAddress });
577
563
 
578
- const claimProtocolFeeIxWithHookAccounts = {
579
- ...claimProtocolFeeIx,
580
- accounts: [...claimProtocolFeeIx.accounts, ...remainingAccounts],
581
- };
582
-
583
- return [...preInstructions, claimProtocolFeeIxWithHookAccounts, ...postInstructions];
564
+ return [...preInstructions, appendRemainingAccounts(claimProtocolFeeIx, remainingAccounts), ...postInstructions];
584
565
  }
585
566
 
586
567
  public static async load(
@@ -3,7 +3,6 @@ import {
3
3
  createSolanaRpc,
4
4
  assertAccountExists,
5
5
  fetchEncodedAccounts,
6
- type AccountRole,
7
6
  type Address,
8
7
  type Account,
9
8
  type Instruction,
@@ -18,7 +17,10 @@ import {
18
17
  findPositionTokenAccount,
19
18
  processAssociatedTokenAccountPair,
20
19
  } from "../utils/ata";
21
- import { toRemainingAccountMeta } from "../utils/transfer_hook";
20
+ import {
21
+ appendRemainingAccounts,
22
+ buildTransferHookScheme,
23
+ } from "../utils/transfer_hook";
22
24
  import {
23
25
  getBinIndex,
24
26
  getBinArrayIndex,
@@ -163,7 +165,29 @@ export class Position {
163
165
  }
164
166
  const [position, binArrays] = arg;
165
167
  this.#account = position;
166
- this.#binArrays.forEach((b, i) => b.refresh(binArrays[i]));
168
+ await Promise.all(this.#binArrays.map((b, i) => b.refresh(binArrays[i])));
169
+ }
170
+
171
+ // Shared by depositByWeight/claimFee/withdraw — each needs the owner's position-NFT token
172
+ // account plus its X/Y ATAs (creating either that don't exist yet, funding wSOL if native).
173
+ // amounts is only relevant for a deposit (it decides how much wSOL to wrap); omitted for
174
+ // claim/withdraw, which only ever receive tokens.
175
+ async #prepareOwnerAccounts(
176
+ owner: TransactionSigner,
177
+ amounts?: { amountX: bigint, amountY: bigint },
178
+ ) {
179
+ return await Promise.all([
180
+ findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
181
+ processAssociatedTokenAccountPair({
182
+ owner,
183
+ tokenMintX: this.#pool.tokenMintX,
184
+ tokenMintY: this.#pool.tokenMintY,
185
+ tokenProgramX: this.#pool.tokenProgramX,
186
+ tokenProgramY: this.#pool.tokenProgramY,
187
+ amountX: amounts?.amountX,
188
+ amountY: amounts?.amountY,
189
+ }),
190
+ ]);
167
191
  }
168
192
 
169
193
  public async depositByWeight(owner: TransactionSigner, {
@@ -189,18 +213,7 @@ export class Position {
189
213
  ataY: tokenOwnerAccountY,
190
214
  preInstructions,
191
215
  postInstructions
192
- }] = await Promise.all([
193
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
194
- processAssociatedTokenAccountPair({
195
- owner,
196
- tokenMintX: this.#pool.tokenMintX,
197
- tokenMintY: this.#pool.tokenMintY,
198
- tokenProgramX: this.#pool.tokenProgramX,
199
- tokenProgramY: this.#pool.tokenProgramY,
200
- amountX,
201
- amountY,
202
- }),
203
- ]);
216
+ }] = await this.#prepareOwnerAccounts(owner, { amountX, amountY });
204
217
 
205
218
  // Both legs move owner -> vault (deposit), signed by owner itself.
206
219
  const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
@@ -212,17 +225,7 @@ export class Position {
212
225
  }),
213
226
  ]);
214
227
 
215
- const groups: generated.AccountGroup[] = [];
216
- const remainingAccounts: { address: Address, role: AccountRole }[] = [];
217
-
218
- if (transferHookXAccounts.length > 0) {
219
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
220
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
221
- }
222
- if (transferHookYAccounts.length > 0) {
223
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
224
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
225
- }
228
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
226
229
 
227
230
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
228
231
  const depositByWeightIx = generated.getDepositByWeightInstruction({
@@ -252,12 +255,7 @@ export class Position {
252
255
  programAddress: this.#pool.programAddress
253
256
  });
254
257
 
255
- const depositByWeightIxWithHookAccounts = {
256
- ...depositByWeightIx,
257
- accounts: [...depositByWeightIx.accounts, ...remainingAccounts],
258
- };
259
-
260
- return [...preInstructions, depositByWeightIxWithHookAccounts, ...postInstructions];
258
+ return [...preInstructions, appendRemainingAccounts(depositByWeightIx, remainingAccounts), ...postInstructions];
261
259
  }
262
260
 
263
261
  async #buildClaimFeeInstruction(
@@ -280,17 +278,7 @@ export class Position {
280
278
  }),
281
279
  ]);
282
280
 
283
- const groups: generated.AccountGroup[] = [];
284
- const remainingAccounts: { address: Address, role: AccountRole }[] = [];
285
-
286
- if (transferHookXAccounts.length > 0) {
287
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
288
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
289
- }
290
- if (transferHookYAccounts.length > 0) {
291
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
292
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
293
- }
281
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
294
282
 
295
283
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
296
284
  const claimFeeIx = generated.getClaimFeeInstruction({
@@ -315,28 +303,19 @@ export class Position {
315
303
  programAddress: this.#pool.programAddress
316
304
  });
317
305
 
318
- return { ...claimFeeIx, accounts: [...claimFeeIx.accounts, ...remainingAccounts] };
306
+ return appendRemainingAccounts(claimFeeIx, remainingAccounts);
319
307
  }
320
308
 
321
309
  public async claimFee(
322
310
  owner: TransactionSigner,
323
- range?: BinIdRange,
311
+ { range }: { range?: BinIdRange } = {},
324
312
  ): Promise<Instruction[]> {
325
313
  const [positionTokenAccount, {
326
314
  ataX: tokenOwnerAccountX,
327
315
  ataY: tokenOwnerAccountY,
328
316
  preInstructions,
329
317
  postInstructions
330
- }] = await Promise.all([
331
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
332
- processAssociatedTokenAccountPair({
333
- owner,
334
- tokenMintX: this.#pool.tokenMintX,
335
- tokenMintY: this.#pool.tokenMintY,
336
- tokenProgramX: this.#pool.tokenProgramX,
337
- tokenProgramY: this.#pool.tokenProgramY,
338
- }),
339
- ]);
318
+ }] = await this.#prepareOwnerAccounts(owner);
340
319
 
341
320
  const claimFeeIx = await this.#buildClaimFeeInstruction(
342
321
  owner, positionTokenAccount, tokenOwnerAccountX, tokenOwnerAccountY, range,
@@ -347,8 +326,7 @@ export class Position {
347
326
 
348
327
  public async withdraw(
349
328
  owner: TransactionSigner,
350
- bpsToRemove: number,
351
- range?: BinIdRange,
329
+ { bpsToRemove, range }: { bpsToRemove: number, range?: BinIdRange },
352
330
  ): Promise<Instruction[]> {
353
331
  const { lowerBinId, upperBinId } = range ?? this.data;
354
332
  assertRangeWithinRange({ lowerBinId, upperBinId }, this.data);
@@ -358,16 +336,7 @@ export class Position {
358
336
  ataY: tokenOwnerAccountY,
359
337
  preInstructions,
360
338
  postInstructions
361
- }] = await Promise.all([
362
- findPositionTokenAccount({ owner: owner.address, positionMint: this.data.positionMint }),
363
- processAssociatedTokenAccountPair({
364
- owner,
365
- tokenMintX: this.#pool.tokenMintX,
366
- tokenMintY: this.#pool.tokenMintY,
367
- tokenProgramX: this.#pool.tokenProgramX,
368
- tokenProgramY: this.#pool.tokenProgramY,
369
- }),
370
- ]);
339
+ }] = await this.#prepareOwnerAccounts(owner);
371
340
 
372
341
  // Both legs move vault -> owner (withdraw), signed by the pool PDA.
373
342
  const [transferHookXAccounts, transferHookYAccounts] = await Promise.all([
@@ -379,17 +348,7 @@ export class Position {
379
348
  }),
380
349
  ]);
381
350
 
382
- const groups: generated.AccountGroup[] = [];
383
- const remainingAccounts: { address: Address, role: AccountRole }[] = [];
384
-
385
- if (transferHookXAccounts.length > 0) {
386
- groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
387
- remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
388
- }
389
- if (transferHookYAccounts.length > 0) {
390
- groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
391
- remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
392
- }
351
+ const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
393
352
 
394
353
  const { lowerBinArray, upperBinArray } = this.binArrayAddresses;
395
354
  const withdrawIx = generated.getWithdrawInstruction({
@@ -415,12 +374,7 @@ export class Position {
415
374
  programAddress: this.#pool.programAddress
416
375
  });
417
376
 
418
- const withdrawIxWithHookAccounts = {
419
- ...withdrawIx,
420
- accounts: [...withdrawIx.accounts, ...remainingAccounts],
421
- };
422
-
423
- return [...preInstructions, withdrawIxWithHookAccounts, ...postInstructions];
377
+ return [...preInstructions, appendRemainingAccounts(withdrawIx, remainingAccounts), ...postInstructions];
424
378
  }
425
379
 
426
380
  public async close(owner: TransactionSigner): Promise<Instruction> {
package/src/utils/ata.ts CHANGED
@@ -41,28 +41,6 @@ export function findPositionTokenAccount({
41
41
  return findAssociatedTokenPdaByTokenProgram({ owner, mint: positionMint, tokenProgram: TOKEN_2022_PROGRAM_ADDRESS });
42
42
  }
43
43
 
44
- // A pool's X/Y vaults — shared by every instruction that moves tokens through a pool
45
- // (withdraw, claim_fee, claim_multiple_fees, claim_protocol_fee, deposit_by_weight, swap).
46
- export async function findPoolTokenVaults({
47
- pool,
48
- tokenMintX,
49
- tokenMintY,
50
- tokenProgramX,
51
- tokenProgramY,
52
- }: {
53
- pool: Address,
54
- tokenMintX: Address,
55
- tokenMintY: Address,
56
- tokenProgramX: Address,
57
- tokenProgramY: Address,
58
- }): Promise<{ tokenVaultX: Address; tokenVaultY: Address }> {
59
- const [tokenVaultX, tokenVaultY] = await Promise.all([
60
- findAssociatedTokenPdaByTokenProgram({ owner: pool, mint: tokenMintX, tokenProgram: tokenProgramX }),
61
- findAssociatedTokenPdaByTokenProgram({ owner: pool, mint: tokenMintY, tokenProgram: tokenProgramY }),
62
- ]);
63
- return { tokenVaultX, tokenVaultY };
64
- }
65
-
66
44
  interface ProcessAssociatedTokenAccountParams {
67
45
  owner: TransactionSigner,
68
46
  mint: Address,
@@ -9,6 +9,7 @@ import {
9
9
  } from "@solana/kit";
10
10
  import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
11
11
  import type { Mint, Extension } from "@solana-program/token-2022";
12
+ import * as generated from "../generated";
12
13
 
13
14
  const EXTRA_ACCOUNT_METAS_SEED = "extra-account-metas";
14
15
 
@@ -288,3 +289,39 @@ export function toRemainingAccountMeta({ address, isSigner, isWritable }: ExtraA
288
289
  : (isWritable ? AccountRole.WRITABLE : AccountRole.READONLY);
289
290
  return { address, role };
290
291
  }
292
+
293
+ export type RemainingAccountMeta = { address: Address, role: AccountRole };
294
+
295
+ // Builds the TransferHookX/TransferHookY groups + their remaining-account metas from a resolved
296
+ // pair of hook accounts — one group per side, omitted entirely when that side has no active hook
297
+ // (mirrors the on-chain program's own RemainingAccountsScheme, which only expects a group to be
298
+ // present when the corresponding mint actually carries a hook). Callers that also need a group
299
+ // ahead of these (e.g. swap's BinArray group) prepend their own groups/accounts to the result.
300
+ export function buildTransferHookScheme(
301
+ transferHookXAccounts: ExtraAccount[],
302
+ transferHookYAccounts: ExtraAccount[],
303
+ ): { groups: generated.AccountGroup[], remainingAccounts: RemainingAccountMeta[] } {
304
+ const groups: generated.AccountGroup[] = [];
305
+ const remainingAccounts: RemainingAccountMeta[] = [];
306
+
307
+ if (transferHookXAccounts.length > 0) {
308
+ groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
309
+ remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
310
+ }
311
+ if (transferHookYAccounts.length > 0) {
312
+ groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
313
+ remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
314
+ }
315
+
316
+ return { groups, remainingAccounts };
317
+ }
318
+
319
+ // Appends resolved remaining-account metas (transfer hook accounts, bin arrays, ...) onto an
320
+ // already-built instruction — the one-line splice every instruction builder in entities/ needs
321
+ // after computing its own RemainingAccountsScheme.
322
+ export function appendRemainingAccounts<TIx extends { accounts?: readonly unknown[] }>(
323
+ instruction: TIx,
324
+ remainingAccounts: RemainingAccountMeta[],
325
+ ): TIx {
326
+ return { ...instruction, accounts: [...(instruction.accounts ?? []), ...remainingAccounts] };
327
+ }