@picon-finance/dlmm-sdk 1.16.3 → 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 +1 -1
- package/dist/entities/bin_array.d.ts +2 -0
- package/dist/entities/bin_array.d.ts.map +1 -1
- package/dist/entities/bin_array.js +10 -0
- package/dist/entities/pool.d.ts +2 -0
- package/dist/entities/pool.d.ts.map +1 -1
- package/dist/entities/pool.js +20 -29
- package/dist/entities/position.d.ts +7 -2
- package/dist/entities/position.d.ts.map +1 -1
- package/dist/entities/position.js +25 -71
- package/dist/utils/ata.d.ts +0 -10
- package/dist/utils/ata.d.ts.map +1 -1
- package/dist/utils/ata.js +0 -9
- package/dist/utils/transfer_hook.d.ts +12 -0
- package/dist/utils/transfer_hook.d.ts.map +1 -1
- package/dist/utils/transfer_hook.js +25 -0
- package/package.json +4 -4
- package/src/entities/bin_array.ts +30 -0
- package/src/entities/pool.ts +29 -31
- package/src/entities/position.ts +38 -84
- package/src/utils/ata.ts +0 -22
- package/src/utils/transfer_hook.ts +37 -0
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
|
|
|
@@ -10,6 +10,7 @@ export declare class BinArray {
|
|
|
10
10
|
refresh(data: Account<generated.BinArray>): Promise<void>;
|
|
11
11
|
refresh(config?: FetchAccountConfig): Promise<void>;
|
|
12
12
|
static loadAll(rpc: ReturnType<typeof createSolanaRpc>, pool: Address, indices: number[], programAddress: Address, config?: FetchAccountsConfig): Promise<BinArray[]>;
|
|
13
|
+
static loadAllMaybe(rpc: ReturnType<typeof createSolanaRpc>, pool: Address, indices: number[], programAddress: Address, config?: FetchAccountsConfig): Promise<Array<BinArray | undefined>>;
|
|
13
14
|
delete(authority: TransactionSigner): Promise<Instruction>;
|
|
14
15
|
}
|
|
15
16
|
export declare function createBinArray({ payer, pool, index, idempotent, }: {
|
|
@@ -33,5 +34,6 @@ export declare function findAllBinArrayAddresses({ pool, indices }: {
|
|
|
33
34
|
indices: number[];
|
|
34
35
|
}, config: ProgramConfig): Promise<Address[]>;
|
|
35
36
|
export declare function fetchAllBinArraysChunked(rpc: ReturnType<typeof createSolanaRpc>, addresses: Address[], config?: FetchAccountsConfig): Promise<Account<generated.BinArray>[]>;
|
|
37
|
+
export declare function fetchAllMaybeBinArraysChunked(rpc: ReturnType<typeof createSolanaRpc>, addresses: Address[], config?: FetchAccountsConfig): Promise<import("@solana/accounts").MaybeAccount<generated.BinArray>[]>;
|
|
36
38
|
export declare function decodeAllBinArrays(maybeAccounts: MaybeEncodedAccount<string>[]): Account<generated.BinArray>[];
|
|
37
39
|
//# sourceMappingURL=bin_array.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin_array.d.ts","sourceRoot":"","sources":["../../src/entities/bin_array.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAEf,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAK/B,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,qBAAa,QAAQ;;IAKnB,OAAO,eAQN;IAED,IAAW,OAAO,oBAAoC;IACtD,IAAW,IAAI,uBAAiC;IAChD,IAAW,IAAI,oBAA6B;IAE/B,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,OAAO,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAQjE,OAAoB,OAAO,CACzB,GAAG,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACvC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,cAAc,EAAE,OAAO,EACvB,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAOrB;IAEY,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAUtE;CACF;AAED,wBAAsB,cAAc,CAClC,EACE,KAAK,EACL,IAAI,EACJ,KAAK,EACL,UAAiB,GAClB,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,EACD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,WAAW,CAAC,CAStB;AAED,wBAAsB,kBAAkB,CACtC,EACE,KAAK,EACL,IAAI,EACJ,OAAO,EACP,UAAiB,GAClB,EAAE;IACD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,EACD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC,CAKxB;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACvC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,OAAO,CAAC,CAGlB;AAED,wBAAsB,wBAAwB,CAC5C,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,EACvD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,OAAO,EAAE,CAAC,CAIpB;AAED,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,EACvC,SAAS,EAAE,OAAO,EAAE,EACpB,MAAM,CAAC,EAAE,mBAAmB,0CAO7B;AAID,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,mBAAmB,CAAC,MAAM,CAAC,EAAE,GAC3C,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAG/B"}
|
|
1
|
+
{"version":3,"file":"bin_array.d.ts","sourceRoot":"","sources":["../../src/entities/bin_array.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,13 @@ export class BinArray {
|
|
|
27
27
|
const accounts = await fetchAllBinArraysChunked(rpc, addresses, config);
|
|
28
28
|
return accounts.map(account => new BinArray(rpc, account, programAddress));
|
|
29
29
|
}
|
|
30
|
+
// Same as loadAll, but for a caller-chosen index range that may include bin arrays nobody has
|
|
31
|
+
// created on-chain yet (e.g. a UI-selected price range) — undefined in place of throwing.
|
|
32
|
+
static async loadAllMaybe(rpc, pool, indices, programAddress, config) {
|
|
33
|
+
const addresses = await findAllBinArrayAddresses({ indices, pool }, { programAddress });
|
|
34
|
+
const maybeAccounts = await fetchAllMaybeBinArraysChunked(rpc, addresses, config);
|
|
35
|
+
return maybeAccounts.map(maybeAccount => maybeAccount.exists ? new BinArray(rpc, maybeAccount, programAddress) : undefined);
|
|
36
|
+
}
|
|
30
37
|
async delete(authority) {
|
|
31
38
|
const adminConfig = await resolveAdminConfigAddress(this.#programAddress);
|
|
32
39
|
return await generated.getDeleteBinArrayInstructionAsync({
|
|
@@ -56,6 +63,9 @@ export async function findAllBinArrayAddresses({ pool, indices }, config) {
|
|
|
56
63
|
export async function fetchAllBinArraysChunked(rpc, addresses, config) {
|
|
57
64
|
return await fetchInChunks(addresses, MAX_ACCOUNTS_PER_RPC_BATCH, chunkAddresses => generated.fetchAllBinArray(rpc, chunkAddresses, config));
|
|
58
65
|
}
|
|
66
|
+
export async function fetchAllMaybeBinArraysChunked(rpc, addresses, config) {
|
|
67
|
+
return await fetchInChunks(addresses, MAX_ACCOUNTS_PER_RPC_BATCH, chunkAddresses => generated.fetchAllMaybeBinArray(rpc, chunkAddresses, config));
|
|
68
|
+
}
|
|
59
69
|
const binArrayDecoder = generated.getBinArrayDecoder();
|
|
60
70
|
export function decodeAllBinArrays(maybeAccounts) {
|
|
61
71
|
assertAccountsExist(maybeAccounts);
|
package/dist/entities/pool.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { generated } from "..";
|
|
|
3
3
|
import { type FeeRates, type QuoteExactInOutput, type QuoteExactOutOutput, type TransferFee } from "../quote";
|
|
4
4
|
import { type ExtraAccount, type TransferAccounts as TransferHookAccounts } from "../utils/transfer_hook";
|
|
5
5
|
import { Position } from "./position";
|
|
6
|
+
import { BinArray } from "./bin_array";
|
|
6
7
|
import { type ProgramConfig } from "./types";
|
|
7
8
|
export declare class Pool {
|
|
8
9
|
#private;
|
|
@@ -30,6 +31,7 @@ export declare class Pool {
|
|
|
30
31
|
getPosition(address: Address, config?: FetchAccountsConfig): Promise<Position>;
|
|
31
32
|
getPositionByPositionMint(positionMint: Address, config?: FetchAccountsConfig): Promise<Position>;
|
|
32
33
|
getAllPositionsByPositionMints(positionMints: Address[], config?: FetchAccountsConfig): Promise<Position[]>;
|
|
34
|
+
getBinArraysForRange(lowerBinId: number, upperBinId: number, config?: FetchAccountsConfig): Promise<Array<BinArray | undefined>>;
|
|
33
35
|
openPosition(owner: TransactionSigner, positionMint: TransactionSigner, { lowerBinId, upperBinId }: {
|
|
34
36
|
lowerBinId: number;
|
|
35
37
|
upperBinId: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEf,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,WAAW,EACjB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/entities/pool.ts"],"names":[],"mappings":"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"}
|
package/dist/entities/pool.js
CHANGED
|
@@ -5,12 +5,12 @@ import { quoteExactIn, quoteExactOut, getPoolFeeRates, } from "../quote";
|
|
|
5
5
|
import { isAccount } from "../utils/type_guards";
|
|
6
6
|
import { resolveAdminConfigAddress } from "./admin_config";
|
|
7
7
|
import { processAssociatedTokenAccountPair } from "../utils/ata";
|
|
8
|
-
import { getBinArrayIndex, generateBinArrayIndicesForSwap, generateBinArrayIndicesForSync, } from "../utils/bin_location";
|
|
8
|
+
import { getBinArrayIndex, getBinArrayIndexSequence, generateBinArrayIndicesForSwap, generateBinArrayIndicesForSync, } from "../utils/bin_location";
|
|
9
9
|
import { resolveTransferFee } from "../utils/transfer_fee";
|
|
10
|
-
import { resolveTransferHookProgram, resolveTransferHookExtraAccounts,
|
|
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
|
-
import { findAllBinArrayAddresses } from "./bin_array";
|
|
13
|
+
import { BinArray, findAllBinArrayAddresses } from "./bin_array";
|
|
14
14
|
export class Pool {
|
|
15
15
|
#programAddress;
|
|
16
16
|
#rpc;
|
|
@@ -64,6 +64,14 @@ export class Pool {
|
|
|
64
64
|
const addresses = await findAllPositionAddresses({ positionMints }, { programAddress: this.#programAddress });
|
|
65
65
|
return await Position.loadAll(this, addresses, config);
|
|
66
66
|
}
|
|
67
|
+
// Unlike #resolveSwapBinArrays (bounded to a fixed traversal window around the active bin) or
|
|
68
|
+
// a position's own bin arrays (bounded to that position's range), this covers a caller-chosen
|
|
69
|
+
// [lowerBinId, upperBinId] — e.g. a UI-selected price range that may extend past what's
|
|
70
|
+
// already loaded. undefined entries mean no bin array has been created there yet.
|
|
71
|
+
async getBinArraysForRange(lowerBinId, upperBinId, config) {
|
|
72
|
+
const indices = getBinArrayIndexSequence(getBinArrayIndex(lowerBinId), getBinArrayIndex(upperBinId));
|
|
73
|
+
return await BinArray.loadAllMaybe(this.#rpc, this.address, indices, this.#programAddress, config);
|
|
74
|
+
}
|
|
67
75
|
async openPosition(owner, positionMint, { lowerBinId, upperBinId }) {
|
|
68
76
|
return await openPosition(this.#rpc, { owner, positionMint, pool: this.address, lowerBinId, upperBinId }, { programAddress: this.#programAddress });
|
|
69
77
|
}
|
|
@@ -139,25 +147,21 @@ export class Pool {
|
|
|
139
147
|
this.resolveTransferHookAccountsX(xTransferAccounts),
|
|
140
148
|
this.resolveTransferHookAccountsY(yTransferAccounts),
|
|
141
149
|
]);
|
|
150
|
+
const hookScheme = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
|
|
142
151
|
const groups = [
|
|
143
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,
|
|
144
158
|
];
|
|
145
|
-
const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
|
|
146
|
-
if (transferHookXAccounts.length > 0) {
|
|
147
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
148
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
149
|
-
}
|
|
150
|
-
if (transferHookYAccounts.length > 0) {
|
|
151
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
152
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
153
|
-
}
|
|
154
159
|
const swapIx = buildSwapIx({
|
|
155
160
|
tokenUserAccountX,
|
|
156
161
|
tokenUserAccountY,
|
|
157
162
|
remainingAccountsScheme: { groups },
|
|
158
163
|
});
|
|
159
|
-
|
|
160
|
-
return [...preInstructions, swapIxWithBinArrays, ...postInstructions];
|
|
164
|
+
return [...preInstructions, appendRemainingAccounts(swapIx, remainingAccounts), ...postInstructions];
|
|
161
165
|
}
|
|
162
166
|
// Public so Position (which only holds a reference to this Pool, not its private mint data)
|
|
163
167
|
// can resolve hook accounts for its own deposit/withdraw/claimFee instructions without ever
|
|
@@ -275,16 +279,7 @@ export class Pool {
|
|
|
275
279
|
source: this.tokenVaultY, mint: this.tokenMintY, destination: tokenAdminAccountY, owner: this.address,
|
|
276
280
|
}),
|
|
277
281
|
]);
|
|
278
|
-
const groups =
|
|
279
|
-
const remainingAccounts = [];
|
|
280
|
-
if (transferHookXAccounts.length > 0) {
|
|
281
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
282
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
283
|
-
}
|
|
284
|
-
if (transferHookYAccounts.length > 0) {
|
|
285
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
286
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
287
|
-
}
|
|
282
|
+
const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
|
|
288
283
|
const claimProtocolFeeIx = await generated.getClaimProtocolFeeInstructionAsync({
|
|
289
284
|
authority,
|
|
290
285
|
pool: this.address,
|
|
@@ -299,11 +294,7 @@ export class Pool {
|
|
|
299
294
|
tokenProgramX: this.tokenProgramX,
|
|
300
295
|
tokenProgramY: this.tokenProgramY,
|
|
301
296
|
}, { programAddress: this.#programAddress });
|
|
302
|
-
|
|
303
|
-
...claimProtocolFeeIx,
|
|
304
|
-
accounts: [...claimProtocolFeeIx.accounts, ...remainingAccounts],
|
|
305
|
-
};
|
|
306
|
-
return [...preInstructions, claimProtocolFeeIxWithHookAccounts, ...postInstructions];
|
|
297
|
+
return [...preInstructions, appendRemainingAccounts(claimProtocolFeeIx, remainingAccounts), ...postInstructions];
|
|
307
298
|
}
|
|
308
299
|
static async load(rpc, address, programAddress, config) {
|
|
309
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?:
|
|
31
|
-
|
|
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":"AAAA,OAAO,EAEL,eAAe,
|
|
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 {
|
|
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.
|
|
100
|
+
await Promise.all(this.#binArrays.map((b, i) => b.refresh(binArrays[i])));
|
|
101
101
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
|
198
|
+
return appendRemainingAccounts(claimFeeIx, remainingAccounts);
|
|
214
199
|
}
|
|
215
|
-
async claimFee(owner, range) {
|
|
216
|
-
const [positionTokenAccount, { ataX: tokenOwnerAccountX, ataY: tokenOwnerAccountY, preInstructions, postInstructions }] = await
|
|
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
|
|
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
|
-
|
|
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 });
|
package/dist/utils/ata.d.ts
CHANGED
|
@@ -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;
|
package/dist/utils/ata.d.ts.map
CHANGED
|
@@ -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;
|
|
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;
|
|
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.
|
|
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.
|
|
56
|
-
"@codama/renderers-js": "^2.3.
|
|
57
|
-
"codama": "^1.
|
|
55
|
+
"@codama/nodes-from-anchor": "^1.5.3",
|
|
56
|
+
"@codama/renderers-js": "^2.3.1",
|
|
57
|
+
"codama": "^1.10.0"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -61,6 +61,24 @@ export class BinArray {
|
|
|
61
61
|
return accounts.map(account => new BinArray(rpc, account, programAddress));
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Same as loadAll, but for a caller-chosen index range that may include bin arrays nobody has
|
|
65
|
+
// created on-chain yet (e.g. a UI-selected price range) — undefined in place of throwing.
|
|
66
|
+
public static async loadAllMaybe(
|
|
67
|
+
rpc: ReturnType<typeof createSolanaRpc>,
|
|
68
|
+
pool: Address,
|
|
69
|
+
indices: number[],
|
|
70
|
+
programAddress: Address,
|
|
71
|
+
config?: FetchAccountsConfig,
|
|
72
|
+
): Promise<Array<BinArray | undefined>> {
|
|
73
|
+
const addresses = await findAllBinArrayAddresses(
|
|
74
|
+
{ indices, pool },
|
|
75
|
+
{ programAddress },
|
|
76
|
+
);
|
|
77
|
+
const maybeAccounts = await fetchAllMaybeBinArraysChunked(rpc, addresses, config);
|
|
78
|
+
return maybeAccounts.map(maybeAccount =>
|
|
79
|
+
maybeAccount.exists ? new BinArray(rpc, maybeAccount, programAddress) : undefined);
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
public async delete(authority: TransactionSigner): Promise<Instruction> {
|
|
65
83
|
const adminConfig = await resolveAdminConfigAddress(this.#programAddress);
|
|
66
84
|
return await generated.getDeleteBinArrayInstructionAsync({
|
|
@@ -147,6 +165,18 @@ export async function fetchAllBinArraysChunked(
|
|
|
147
165
|
);
|
|
148
166
|
}
|
|
149
167
|
|
|
168
|
+
export async function fetchAllMaybeBinArraysChunked(
|
|
169
|
+
rpc: ReturnType<typeof createSolanaRpc>,
|
|
170
|
+
addresses: Address[],
|
|
171
|
+
config?: FetchAccountsConfig,
|
|
172
|
+
) {
|
|
173
|
+
return await fetchInChunks(
|
|
174
|
+
addresses,
|
|
175
|
+
MAX_ACCOUNTS_PER_RPC_BATCH,
|
|
176
|
+
chunkAddresses => generated.fetchAllMaybeBinArray(rpc, chunkAddresses, config),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
150
180
|
const binArrayDecoder = generated.getBinArrayDecoder();
|
|
151
181
|
|
|
152
182
|
export function decodeAllBinArrays(
|
package/src/entities/pool.ts
CHANGED
|
@@ -28,14 +28,16 @@ import { resolveAdminConfigAddress } from "./admin_config";
|
|
|
28
28
|
import { processAssociatedTokenAccountPair } from "../utils/ata";
|
|
29
29
|
import {
|
|
30
30
|
getBinArrayIndex,
|
|
31
|
+
getBinArrayIndexSequence,
|
|
31
32
|
generateBinArrayIndicesForSwap,
|
|
32
33
|
generateBinArrayIndicesForSync,
|
|
33
34
|
} from "../utils/bin_location";
|
|
34
35
|
import { resolveTransferFee } from "../utils/transfer_fee";
|
|
35
36
|
import {
|
|
37
|
+
appendRemainingAccounts,
|
|
38
|
+
buildTransferHookScheme,
|
|
36
39
|
resolveTransferHookProgram,
|
|
37
40
|
resolveTransferHookExtraAccounts,
|
|
38
|
-
toRemainingAccountMeta,
|
|
39
41
|
type ExtraAccount,
|
|
40
42
|
type TransferAccounts as TransferHookAccounts,
|
|
41
43
|
} from "../utils/transfer_hook";
|
|
@@ -47,7 +49,7 @@ import {
|
|
|
47
49
|
findPositionAddress,
|
|
48
50
|
findAllPositionAddresses,
|
|
49
51
|
} from "./position";
|
|
50
|
-
import { findAllBinArrayAddresses } from "./bin_array";
|
|
52
|
+
import { BinArray, findAllBinArrayAddresses } from "./bin_array";
|
|
51
53
|
import { type ProgramConfig } from "./types";
|
|
52
54
|
|
|
53
55
|
export class Pool {
|
|
@@ -141,6 +143,22 @@ export class Pool {
|
|
|
141
143
|
return await Position.loadAll(this, addresses, config);
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
// Unlike #resolveSwapBinArrays (bounded to a fixed traversal window around the active bin) or
|
|
147
|
+
// a position's own bin arrays (bounded to that position's range), this covers a caller-chosen
|
|
148
|
+
// [lowerBinId, upperBinId] — e.g. a UI-selected price range that may extend past what's
|
|
149
|
+
// already loaded. undefined entries mean no bin array has been created there yet.
|
|
150
|
+
public async getBinArraysForRange(
|
|
151
|
+
lowerBinId: number,
|
|
152
|
+
upperBinId: number,
|
|
153
|
+
config?: FetchAccountsConfig,
|
|
154
|
+
): Promise<Array<BinArray | undefined>> {
|
|
155
|
+
const indices = getBinArrayIndexSequence(
|
|
156
|
+
getBinArrayIndex(lowerBinId),
|
|
157
|
+
getBinArrayIndex(upperBinId),
|
|
158
|
+
);
|
|
159
|
+
return await BinArray.loadAllMaybe(this.#rpc, this.address, indices, this.#programAddress, config);
|
|
160
|
+
}
|
|
161
|
+
|
|
144
162
|
public async openPosition(
|
|
145
163
|
owner: TransactionSigner,
|
|
146
164
|
positionMint: TransactionSigner,
|
|
@@ -294,28 +312,23 @@ export class Pool {
|
|
|
294
312
|
this.resolveTransferHookAccountsY(yTransferAccounts),
|
|
295
313
|
]);
|
|
296
314
|
|
|
315
|
+
const hookScheme = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
|
|
297
316
|
const groups: generated.AccountGroup[] = [
|
|
298
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,
|
|
299
323
|
];
|
|
300
|
-
const remainingAccounts = binArrayAddresses.map(address => ({ address, role: AccountRole.WRITABLE }));
|
|
301
|
-
|
|
302
|
-
if (transferHookXAccounts.length > 0) {
|
|
303
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
304
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
305
|
-
}
|
|
306
|
-
if (transferHookYAccounts.length > 0) {
|
|
307
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
308
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
309
|
-
}
|
|
310
324
|
|
|
311
325
|
const swapIx = buildSwapIx({
|
|
312
326
|
tokenUserAccountX,
|
|
313
327
|
tokenUserAccountY,
|
|
314
328
|
remainingAccountsScheme: { groups },
|
|
315
329
|
});
|
|
316
|
-
const swapIxWithBinArrays = { ...swapIx, accounts: [...(swapIx.accounts ?? []), ...remainingAccounts] };
|
|
317
330
|
|
|
318
|
-
return [...preInstructions,
|
|
331
|
+
return [...preInstructions, appendRemainingAccounts(swapIx, remainingAccounts), ...postInstructions];
|
|
319
332
|
}
|
|
320
333
|
|
|
321
334
|
// Public so Position (which only holds a reference to this Pool, not its private mint data)
|
|
@@ -531,17 +544,7 @@ export class Pool {
|
|
|
531
544
|
}),
|
|
532
545
|
]);
|
|
533
546
|
|
|
534
|
-
const groups
|
|
535
|
-
const remainingAccounts: { address: Address, role: AccountRole }[] = [];
|
|
536
|
-
|
|
537
|
-
if (transferHookXAccounts.length > 0) {
|
|
538
|
-
groups.push({ kind: generated.AccountKind.TransferHookX, count: transferHookXAccounts.length });
|
|
539
|
-
remainingAccounts.push(...transferHookXAccounts.map(toRemainingAccountMeta));
|
|
540
|
-
}
|
|
541
|
-
if (transferHookYAccounts.length > 0) {
|
|
542
|
-
groups.push({ kind: generated.AccountKind.TransferHookY, count: transferHookYAccounts.length });
|
|
543
|
-
remainingAccounts.push(...transferHookYAccounts.map(toRemainingAccountMeta));
|
|
544
|
-
}
|
|
547
|
+
const { groups, remainingAccounts } = buildTransferHookScheme(transferHookXAccounts, transferHookYAccounts);
|
|
545
548
|
|
|
546
549
|
const claimProtocolFeeIx = await generated.getClaimProtocolFeeInstructionAsync({
|
|
547
550
|
authority,
|
|
@@ -558,12 +561,7 @@ export class Pool {
|
|
|
558
561
|
tokenProgramY: this.tokenProgramY,
|
|
559
562
|
}, { programAddress: this.#programAddress });
|
|
560
563
|
|
|
561
|
-
|
|
562
|
-
...claimProtocolFeeIx,
|
|
563
|
-
accounts: [...claimProtocolFeeIx.accounts, ...remainingAccounts],
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
return [...preInstructions, claimProtocolFeeIxWithHookAccounts, ...postInstructions];
|
|
564
|
+
return [...preInstructions, appendRemainingAccounts(claimProtocolFeeIx, remainingAccounts), ...postInstructions];
|
|
567
565
|
}
|
|
568
566
|
|
|
569
567
|
public static async load(
|
package/src/entities/position.ts
CHANGED
|
@@ -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 {
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|