@w3lib/solana-batch-call 0.3.0 → 0.4.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +74 -1
  3. package/dist/address.d.ts +2 -0
  4. package/dist/address.d.ts.map +1 -1
  5. package/dist/address.js +8 -0
  6. package/dist/address.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/liquidity/amm.d.ts +7 -0
  12. package/dist/liquidity/amm.d.ts.map +1 -0
  13. package/dist/liquidity/amm.js +307 -0
  14. package/dist/liquidity/amm.js.map +1 -0
  15. package/dist/liquidity/clmm.d.ts +18 -0
  16. package/dist/liquidity/clmm.d.ts.map +1 -0
  17. package/dist/liquidity/clmm.js +85 -0
  18. package/dist/liquidity/clmm.js.map +1 -0
  19. package/dist/liquidity/common.d.ts +94 -0
  20. package/dist/liquidity/common.d.ts.map +1 -0
  21. package/dist/liquidity/common.js +228 -0
  22. package/dist/liquidity/common.js.map +1 -0
  23. package/dist/liquidity/index.d.ts +34 -0
  24. package/dist/liquidity/index.d.ts.map +1 -0
  25. package/dist/liquidity/index.js +157 -0
  26. package/dist/liquidity/index.js.map +1 -0
  27. package/dist/liquidity/orca.d.ts +6 -0
  28. package/dist/liquidity/orca.d.ts.map +1 -0
  29. package/dist/liquidity/orca.js +303 -0
  30. package/dist/liquidity/orca.js.map +1 -0
  31. package/dist/liquidity/raydiumClmm.d.ts +6 -0
  32. package/dist/liquidity/raydiumClmm.d.ts.map +1 -0
  33. package/dist/liquidity/raydiumClmm.js +307 -0
  34. package/dist/liquidity/raydiumClmm.js.map +1 -0
  35. package/dist/liquidity/types.d.ts +150 -0
  36. package/dist/liquidity/types.d.ts.map +1 -0
  37. package/dist/liquidity/types.js +2 -0
  38. package/dist/liquidity/types.js.map +1 -0
  39. package/dist/lp.d.ts +45 -0
  40. package/dist/lp.d.ts.map +1 -1
  41. package/dist/lp.js +8 -7
  42. package/dist/lp.js.map +1 -1
  43. package/dist/lpMath.d.ts +45 -0
  44. package/dist/lpMath.d.ts.map +1 -1
  45. package/dist/lpMath.js +189 -0
  46. package/dist/lpMath.js.map +1 -1
  47. package/dist/subpaths/liquidity.d.ts +23 -0
  48. package/dist/subpaths/liquidity.d.ts.map +1 -0
  49. package/dist/subpaths/liquidity.js +19 -0
  50. package/dist/subpaths/liquidity.js.map +1 -0
  51. package/dist/subpaths/lp.d.ts +1 -1
  52. package/dist/subpaths/lp.d.ts.map +1 -1
  53. package/dist/subpaths/lp.js +1 -1
  54. package/dist/subpaths/lp.js.map +1 -1
  55. package/package.json +17 -10
  56. package/src/address.ts +9 -0
  57. package/src/index.ts +1 -1
  58. package/src/liquidity/amm.ts +353 -0
  59. package/src/liquidity/clmm.ts +108 -0
  60. package/src/liquidity/common.ts +285 -0
  61. package/src/liquidity/index.ts +177 -0
  62. package/src/liquidity/orca.ts +344 -0
  63. package/src/liquidity/raydiumClmm.ts +348 -0
  64. package/src/liquidity/types.ts +158 -0
  65. package/src/lp.ts +9 -8
  66. package/src/lpMath.ts +215 -0
  67. package/src/subpaths/liquidity.ts +45 -0
  68. package/src/subpaths/lp.ts +9 -0
@@ -0,0 +1,85 @@
1
+ import { lpPositions } from '../lp.js';
2
+ import { MAX_TICK, MIN_TICK, getLiquidityForAmounts, nearestUsableTick, priceToTick, sqrtPriceAtTick, sqrtPriceToPrice, tickToPrice, } from '../lpMath.js';
3
+ /** 新建仓位的 tick 区间:fullRange / tickLower + tickUpper / priceLower + priceUpper(token1 / token0)三选一 */
4
+ export function resolveRange(program, params, token0, token1, tickSpacing) {
5
+ const byTicks = params.tickLower !== undefined || params.tickUpper !== undefined;
6
+ const byPrices = params.priceLower !== undefined || params.priceUpper !== undefined;
7
+ if (Number(!!params.fullRange) + Number(byTicks) + Number(byPrices) !== 1) {
8
+ throw new Error('Pass exactly one of fullRange, tickLower + tickUpper, or priceLower + priceUpper');
9
+ }
10
+ let lower;
11
+ let upper;
12
+ if (params.fullRange) {
13
+ lower = Math.ceil(MIN_TICK / tickSpacing) * tickSpacing;
14
+ upper = Math.floor(MAX_TICK / tickSpacing) * tickSpacing;
15
+ }
16
+ else if (byTicks) {
17
+ if (params.tickLower === undefined || params.tickUpper === undefined) {
18
+ throw new Error('Pass both tickLower and tickUpper');
19
+ }
20
+ lower = params.tickLower;
21
+ upper = params.tickUpper;
22
+ for (const tick of [lower, upper]) {
23
+ if (!Number.isInteger(tick) || tick < MIN_TICK || tick > MAX_TICK || tick % tickSpacing !== 0) {
24
+ throw new RangeError(`tick ${tick} must be an integer multiple of tickSpacing ${tickSpacing} within [${MIN_TICK}, ${MAX_TICK}]`);
25
+ }
26
+ }
27
+ }
28
+ else {
29
+ if (params.priceLower === undefined || params.priceUpper === undefined) {
30
+ throw new Error('Pass both priceLower and priceUpper');
31
+ }
32
+ if (token0.decimals === null || token1.decimals === null) {
33
+ throw new Error('Cannot read token decimals to convert prices; pass ticks instead');
34
+ }
35
+ const ticks = [params.priceLower, params.priceUpper].map((price) => {
36
+ return nearestUsableTick(priceToTick(program, price, token0.decimals, token1.decimals), tickSpacing);
37
+ });
38
+ [lower, upper] = ticks[0] <= ticks[1] ? ticks : [ticks[1], ticks[0]];
39
+ }
40
+ if (lower >= upper) {
41
+ throw new RangeError(`The price range is too narrow: tickLower ${lower} must be below tickUpper ${upper} (tickSpacing ${tickSpacing})`);
42
+ }
43
+ return [lower, upper];
44
+ }
45
+ /** 按输入的数量算添加的流动性;价格在区间外时只需要一种代币,给错了另一种会报错 */
46
+ export function liquidityFor(program, tick, sqrtPrice, tickLower, tickUpper, amount0, amount1, token0, token1) {
47
+ const name = (t) => t.symbol ?? t.mint;
48
+ if (amount0 === undefined && amount1 === undefined) {
49
+ throw new Error('Pass the amount of at least one token');
50
+ }
51
+ if (amount1 === undefined && (tick >= tickUpper || sqrtPrice >= sqrtPriceAtTick(program, tickUpper))) {
52
+ throw new Error(`The current price is above the range: the position takes only ${name(token1)} (token1); pass amount1 instead`);
53
+ }
54
+ if (amount0 === undefined && (tick < tickLower || sqrtPrice <= sqrtPriceAtTick(program, tickLower))) {
55
+ throw new Error(`The current price is below the range: the position takes only ${name(token0)} (token0); pass amount0 instead`);
56
+ }
57
+ const liquidity = getLiquidityForAmounts(tick, sqrtPrice, sqrtPriceAtTick(program, tickLower), sqrtPriceAtTick(program, tickUpper), amount0, amount1, tickLower, tickUpper);
58
+ if (liquidity === 0n) {
59
+ throw new Error('Amount too small: the liquidity rounds to 0');
60
+ }
61
+ if (liquidity >= 1n << 128n) {
62
+ throw new RangeError('Amount too large');
63
+ }
64
+ return liquidity;
65
+ }
66
+ /** 计划里的价格字段(token1 / token0,按精度换算,只用于展示) */
67
+ export function priceInfo(tick, sqrtPrice, token0, token1, tickLower, tickUpper) {
68
+ const known = token0.decimals !== null && token1.decimals !== null;
69
+ return {
70
+ tick,
71
+ price: known ? sqrtPriceToPrice(sqrtPrice, token0.decimals, token1.decimals) : null,
72
+ priceLower: known ? tickToPrice(tickLower, token0.decimals, token1.decimals) : null,
73
+ priceUpper: known ? tickToPrice(tickUpper, token0.decimals, token1.decimals) : null,
74
+ };
75
+ }
76
+ /** 已有的仓位:用查询拿到数量、手续费、价格(要求 owner 持有仓位 NFT 的关联代币账户) */
77
+ export async function queryPosition(ctx, protocol, positionMint) {
78
+ const list = await lpPositions(ctx.client, ctx.owner, { protocols: [protocol], mints: [positionMint], includeClosed: true, signal: ctx.signal });
79
+ const found = list.find((p) => p.type === 'clmm' && p.positionMint === positionMint);
80
+ if (!found) {
81
+ throw new Error(`${ctx.owner} does not hold the ${protocol} position ${positionMint} (in its associated token account)`);
82
+ }
83
+ return found;
84
+ }
85
+ //# sourceMappingURL=clmm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clmm.js","sourceRoot":"","sources":["../../src/liquidity/clmm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { SolanaClient } from '../client.js';
2
+ import { type AccountInfo } from '../layout.js';
3
+ import type { SolanaLpPosition, SolanaLpToken } from '../lp.js';
4
+ import type { Instruction } from '../write/transaction.js';
5
+ import type { SolanaLiquidityOptions, SolanaLiquidityPlan, SolanaPositionRef } from './types.js';
6
+ export declare const MEMO_PROGRAM_ID = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
7
+ export declare const RENT_SYSVAR_ID = "SysvarRent111111111111111111111111111111111";
8
+ export declare const DEFAULT_ADDRESS = "11111111111111111111111111111111";
9
+ export interface Ctx {
10
+ client: SolanaClient;
11
+ owner: string;
12
+ recipient: string;
13
+ slippage: number;
14
+ native: boolean;
15
+ signal: AbortSignal | undefined;
16
+ }
17
+ export declare function createCtx(client: SolanaClient, owner: string, options: SolanaLiquidityOptions): Ctx;
18
+ export { Bytes } from '../lp.js';
19
+ /** 按字段顺序写指令数据(小端) */
20
+ export declare class Writer {
21
+ #private;
22
+ bytes(values: ArrayLike<number>): this;
23
+ u8(v: number): this;
24
+ bool(v: boolean): this;
25
+ i32(v: number): this;
26
+ u64(v: bigint): this;
27
+ u128(v: bigint): this;
28
+ build(): Uint8Array;
29
+ }
30
+ /** Anchor 指令判别符:sha256("global:<名称>") 的前 8 字节 */
31
+ export declare function anchorIx(name: string): Uint8Array;
32
+ export declare const w: (pubkey: string, isSigner?: boolean) => {
33
+ pubkey: string;
34
+ isSigner: boolean;
35
+ isWritable: boolean;
36
+ };
37
+ export declare const r: (pubkey: string, isSigner?: boolean) => {
38
+ pubkey: string;
39
+ isSigner: boolean;
40
+ isWritable: boolean;
41
+ };
42
+ /** 读账户,缺失时报错 */
43
+ export declare function mustAccounts(ctx: Ctx, addresses: readonly string[], what: (i: number) => string): Promise<AccountInfo[]>;
44
+ /** 代币的 mint 信息:所属的代币程序、精度 */
45
+ export interface MintMeta {
46
+ mint: string;
47
+ program: string;
48
+ decimals: number;
49
+ }
50
+ /**
51
+ * pool:池子里的两种代币。带转账手续费的 Token-2022 代币不支持(程序按扣费前 / 后的数量检查上下限,计划里的数量会对不上,
52
+ * 手续费超过滑点时交易一定失败),构建时报错;挖矿奖励的代币不检查(只影响到账数量)
53
+ */
54
+ export declare function mintMeta(mint: string, account: AccountInfo, pool?: boolean): MintMeta;
55
+ /** 代币信息(symbol / 精度),与 getLpPositions 的格式一致 */
56
+ export declare function tokenInfo(ctx: Ctx, mints: readonly MintMeta[]): Promise<SolanaLpToken[]>;
57
+ export declare function fmt(value: bigint, token: SolanaLpToken): string | null;
58
+ /** 解析输入的数量:amount(最小单位)和 formatted 二选一,都没给时返回 undefined */
59
+ export declare function parseAmount(raw: bigint | number | string | undefined, formatted: string | undefined, decimals: number, name: string): bigint | undefined;
60
+ /** 按滑点向下取:value × (1 − slippage) */
61
+ export declare function minus(value: bigint, slippage: number): bigint;
62
+ /** 按滑点向上取:value × (1 + slippage),向上取整 */
63
+ export declare function plus(value: bigint, slippage: number): bigint;
64
+ /** 移除的数量:percent(百分数)或 liquidity,二选一,默认全部 */
65
+ export declare function removeAmount(total: bigint, percent: number | undefined, liquidity: bigint | number | string | undefined): bigint;
66
+ /** 用 SOL 的是哪一边 */
67
+ export declare const nativeSide: (index: number | null) => "token0" | "token1" | null;
68
+ /**
69
+ * owner 的代币账户(ATA):添加时要付出的、移除时要收到的。
70
+ * 不存在时创建(setup);wSOL 且 native 时:添加前把差额 SOL 包装进去,最后(原来没有的)关闭换回 SOL
71
+ */
72
+ export interface TokenAccounts {
73
+ /** 每个 mint 的 ATA */
74
+ accounts: string[];
75
+ /** 创建缺少的代币账户 */
76
+ setup: Instruction[];
77
+ /** 包装 SOL(转入 + SyncNative):放在主指令前、同一步里(主指令失败时不会留下包装好的 SOL) */
78
+ wrap: Instruction[];
79
+ cleanup: Instruction[];
80
+ /** 哪一边用 SOL(下标),没有时为 null */
81
+ nativeIndex: number | null;
82
+ }
83
+ export declare function prepareTokenAccounts(ctx: Ctx, mints: readonly MintMeta[], pay: ReadonlyArray<bigint | null>): Promise<TokenAccounts>;
84
+ /** 仓位引用里的字段 */
85
+ export declare function refMint(ref: SolanaPositionRef | SolanaLpPosition): string;
86
+ export declare function refPool(ref: SolanaPositionRef | SolanaLpPosition): string;
87
+ /** 新的仓位 NFT mint:WebCrypto 生成 Ed25519 密钥,secretKey 是 32 字节种子(PKCS#8 的最后 32 字节) */
88
+ export declare function newMintKeypair(): Promise<{
89
+ address: string;
90
+ secretKey: Uint8Array;
91
+ }>;
92
+ type PlanInput = Omit<SolanaLiquidityPlan, 'owner' | 'amount0Formatted' | 'amount1Formatted' | 'fees0Formatted' | 'fees1Formatted'>;
93
+ export declare function makePlan(ctx: Ctx, input: PlanInput): SolanaLiquidityPlan;
94
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/liquidity/common.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,228 @@
1
+ import { sha256 } from '@noble/hashes/sha2.js';
2
+ import { encodeAddress, getAssociatedTokenAddress, isAddress } from '../address.js';
3
+ import { NATIVE_MINT, SYSTEM_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../constants.js';
4
+ import { formatUnits, parseMint, parseTokenAccount, parseTransferFeeConfig, parseUnits } from '../layout.js';
5
+ import { closeAccount, createAssociatedTokenAccountIdempotent, systemTransfer } from '../write/instructions.js';
6
+ export const MEMO_PROGRAM_ID = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
7
+ export const RENT_SYSVAR_ID = 'SysvarRent111111111111111111111111111111111';
8
+ export const DEFAULT_ADDRESS = SYSTEM_PROGRAM_ID;
9
+ export function createCtx(client, owner, options) {
10
+ for (const address of [owner, options.recipient ?? owner]) {
11
+ if (!isAddress(address)) {
12
+ throw new Error(`Invalid address: ${address}`);
13
+ }
14
+ }
15
+ const slippage = options.slippage ?? 0.005;
16
+ if (!(slippage >= 0 && slippage < 1)) {
17
+ throw new RangeError(`slippage must be in [0, 1): ${slippage}`);
18
+ }
19
+ return { client, owner, recipient: options.recipient ?? owner, slippage, native: options.native ?? true, signal: options.signal };
20
+ }
21
+ export { Bytes } from '../lp.js';
22
+ /** 按字段顺序写指令数据(小端) */
23
+ export class Writer {
24
+ #parts = [];
25
+ bytes(values) {
26
+ for (let i = 0; i < values.length; i++)
27
+ this.#parts.push(values[i]);
28
+ return this;
29
+ }
30
+ u8(v) {
31
+ return this.bytes([v & 0xff]);
32
+ }
33
+ bool(v) {
34
+ return this.u8(v ? 1 : 0);
35
+ }
36
+ i32(v) {
37
+ const b = new Uint8Array(4);
38
+ new DataView(b.buffer).setInt32(0, v, true);
39
+ return this.bytes(b);
40
+ }
41
+ u64(v) {
42
+ if (v < 0n || v >= 1n << 64n)
43
+ throw new RangeError(`u64 out of range: ${v}`);
44
+ const b = new Uint8Array(8);
45
+ new DataView(b.buffer).setBigUint64(0, v, true);
46
+ return this.bytes(b);
47
+ }
48
+ u128(v) {
49
+ if (v < 0n || v >= 1n << 128n)
50
+ throw new RangeError(`u128 out of range: ${v}`);
51
+ return this.u64(v & ((1n << 64n) - 1n)).u64(v >> 64n);
52
+ }
53
+ build() {
54
+ return new Uint8Array(this.#parts);
55
+ }
56
+ }
57
+ /** Anchor 指令判别符:sha256("global:<名称>") 的前 8 字节 */
58
+ export function anchorIx(name) {
59
+ return sha256(new TextEncoder().encode(`global:${name}`)).subarray(0, 8);
60
+ }
61
+ export const w = (pubkey, isSigner = false) => ({ pubkey, isSigner, isWritable: true });
62
+ export const r = (pubkey, isSigner = false) => ({ pubkey, isSigner, isWritable: false });
63
+ /** 读账户,缺失时报错 */
64
+ export async function mustAccounts(ctx, addresses, what) {
65
+ const accounts = await ctx.client.accounts(addresses, { signal: ctx.signal });
66
+ return accounts.map((a, i) => {
67
+ if (!a) {
68
+ throw new Error(`${what(i)} not found: ${addresses[i]}`);
69
+ }
70
+ return a;
71
+ });
72
+ }
73
+ /**
74
+ * pool:池子里的两种代币。带转账手续费的 Token-2022 代币不支持(程序按扣费前 / 后的数量检查上下限,计划里的数量会对不上,
75
+ * 手续费超过滑点时交易一定失败),构建时报错;挖矿奖励的代币不检查(只影响到账数量)
76
+ */
77
+ export function mintMeta(mint, account, pool = true) {
78
+ if (account.owner !== TOKEN_PROGRAM_ID && account.owner !== TOKEN_2022_PROGRAM_ID) {
79
+ throw new Error(`${mint} is not a token mint`);
80
+ }
81
+ if (pool && account.owner === TOKEN_2022_PROGRAM_ID) {
82
+ const fee = parseTransferFeeConfig(account.data);
83
+ if (fee && (fee.older.basisPoints > 0 || fee.newer.basisPoints > 0)) {
84
+ throw new Error(`${mint} is a Token-2022 token with a transfer fee, which is not supported`);
85
+ }
86
+ }
87
+ return { mint, program: account.owner, decimals: parseMint(account.data).decimals };
88
+ }
89
+ /** 代币信息(symbol / 精度),与 getLpPositions 的格式一致 */
90
+ export async function tokenInfo(ctx, mints) {
91
+ const details = await ctx.client.tokens(mints.map((m) => m.mint), { fields: ['symbol', 'decimals'], signal: ctx.signal });
92
+ return mints.map((m, i) => ({ mint: m.mint, symbol: details[i]?.symbol ?? null, decimals: details[i]?.decimals ?? m.decimals }));
93
+ }
94
+ export function fmt(value, token) {
95
+ return token.decimals === null ? null : formatUnits(value, token.decimals);
96
+ }
97
+ /** 解析输入的数量:amount(最小单位)和 formatted 二选一,都没给时返回 undefined */
98
+ export function parseAmount(raw, formatted, decimals, name) {
99
+ if (raw !== undefined && formatted !== undefined) {
100
+ throw new Error(`Pass either ${name} or ${name}Formatted, not both`);
101
+ }
102
+ let value;
103
+ if (formatted !== undefined) {
104
+ value = parseUnits(formatted, decimals);
105
+ }
106
+ else if (raw !== undefined) {
107
+ if (typeof raw === 'number' && !Number.isSafeInteger(raw)) {
108
+ throw new RangeError(`${name} must be an integer (raw units); use ${name}Formatted for decimals`);
109
+ }
110
+ value = BigInt(raw);
111
+ }
112
+ else {
113
+ return undefined;
114
+ }
115
+ if (value < 0n) {
116
+ throw new RangeError(`${name} must not be negative`);
117
+ }
118
+ return value;
119
+ }
120
+ /** 按滑点向下取:value × (1 − slippage) */
121
+ export function minus(value, slippage) {
122
+ return (value * (1000000n - BigInt(Math.round(slippage * 1e6)))) / 1000000n;
123
+ }
124
+ /** 按滑点向上取:value × (1 + slippage),向上取整 */
125
+ export function plus(value, slippage) {
126
+ return (value * (1000000n + BigInt(Math.round(slippage * 1e6))) + 999999n) / 1000000n;
127
+ }
128
+ /** 移除的数量:percent(百分数)或 liquidity,二选一,默认全部 */
129
+ export function removeAmount(total, percent, liquidity) {
130
+ if (percent !== undefined && liquidity !== undefined) {
131
+ throw new Error('Pass either percent or liquidity, not both');
132
+ }
133
+ if (liquidity !== undefined) {
134
+ const value = BigInt(liquidity);
135
+ if (value <= 0n || value > total) {
136
+ throw new RangeError(`liquidity must be in (0, ${total}]: ${value}`);
137
+ }
138
+ return value;
139
+ }
140
+ const p = percent ?? 100;
141
+ if (!(p > 0 && p <= 100)) {
142
+ throw new RangeError(`percent must be in (0, 100]: ${p}`);
143
+ }
144
+ const amount = p === 100 ? total : (total * BigInt(Math.round(p * 10_000))) / 1000000n;
145
+ if (amount === 0n) {
146
+ throw new RangeError(`${p}% of ${total} rounds to 0`);
147
+ }
148
+ return amount;
149
+ }
150
+ /** 用 SOL 的是哪一边 */
151
+ export const nativeSide = (index) => (index === 0 ? 'token0' : index === 1 ? 'token1' : null);
152
+ /** SPL Token SyncNative:把 wSOL 账户的 SOL 余额同步成代币余额 */
153
+ function syncNative(account) {
154
+ return { programId: TOKEN_PROGRAM_ID, keys: [w(account)], data: new Uint8Array([17]) };
155
+ }
156
+ export async function prepareTokenAccounts(ctx, mints, pay) {
157
+ const accounts = mints.map((m) => getAssociatedTokenAddress(ctx.owner, m.mint, m.program));
158
+ const existing = await ctx.client.accounts(accounts, { signal: ctx.signal });
159
+ const setup = [];
160
+ const wrap = [];
161
+ const cleanup = [];
162
+ let nativeIndex = null;
163
+ mints.forEach((m, i) => {
164
+ const account = accounts[i];
165
+ const info = existing[i];
166
+ if (!info) {
167
+ setup.push(createAssociatedTokenAccountIdempotent(ctx.owner, account, ctx.owner, m.mint, m.program));
168
+ }
169
+ if (m.mint === NATIVE_MINT && ctx.native) {
170
+ // 添加时用 SOL 支付(包装差额);收取时只有原来没有 wSOL 账户(用完关闭)才是收到 SOL,否则留在原有的 wSOL 账户里
171
+ if (pay[i] != null || !info) {
172
+ nativeIndex = i;
173
+ }
174
+ const need = pay[i] ?? 0n;
175
+ const balance = info ? safeAmount(info) : 0n;
176
+ if (need > balance) {
177
+ wrap.push(systemTransfer(ctx.owner, account, need - balance), syncNative(account));
178
+ }
179
+ if (!info) {
180
+ // 原来没有 wSOL 账户:用完关闭,剩余的 wSOL 和租金换回 SOL
181
+ cleanup.push(closeAccount(account, ctx.owner, ctx.owner, TOKEN_PROGRAM_ID));
182
+ }
183
+ }
184
+ });
185
+ return { accounts, setup, wrap, cleanup, nativeIndex };
186
+ }
187
+ function safeAmount(account) {
188
+ try {
189
+ return parseTokenAccount(account.data).amount;
190
+ }
191
+ catch {
192
+ return 0n;
193
+ }
194
+ }
195
+ /** 仓位引用里的字段 */
196
+ export function refMint(ref) {
197
+ const mint = 'positionMint' in ref ? ref.positionMint : undefined;
198
+ if (!mint || !isAddress(mint)) {
199
+ throw new Error('position.positionMint is required for Raydium CLMM / Orca Whirlpool positions');
200
+ }
201
+ return mint;
202
+ }
203
+ export function refPool(ref) {
204
+ if (!ref.pool || !isAddress(ref.pool)) {
205
+ throw new Error('position.pool is required for Raydium AMM v4 / CPMM positions');
206
+ }
207
+ return ref.pool;
208
+ }
209
+ /** 新的仓位 NFT mint:WebCrypto 生成 Ed25519 密钥,secretKey 是 32 字节种子(PKCS#8 的最后 32 字节) */
210
+ export async function newMintKeypair() {
211
+ const pair = (await crypto.subtle.generateKey('Ed25519', true, ['sign', 'verify']));
212
+ const [publicKey, pkcs8] = await Promise.all([crypto.subtle.exportKey('raw', pair.publicKey), crypto.subtle.exportKey('pkcs8', pair.privateKey)]);
213
+ return { address: encodeAddress(new Uint8Array(publicKey)), secretKey: new Uint8Array(pkcs8).slice(-32) };
214
+ }
215
+ export function makePlan(ctx, input) {
216
+ const { token0, token1 } = input;
217
+ return {
218
+ ...input,
219
+ owner: ctx.owner,
220
+ amount0Formatted: fmt(BigInt(input.amount0), token0),
221
+ amount1Formatted: fmt(BigInt(input.amount1), token1),
222
+ fees0Formatted: fmt(BigInt(input.fees0), token0),
223
+ fees1Formatted: fmt(BigInt(input.fees1), token1),
224
+ // 空的步骤去掉(如不需要创建账户时的 setup)
225
+ steps: input.steps.filter((s) => s.instructions.length > 0),
226
+ };
227
+ }
228
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/liquidity/common.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { SolanaClient } from '../client.js';
2
+ import { type SignerInput } from '../write/signer.js';
3
+ import type { SolanaAddLiquidityParams, SolanaCollectFeesParams, SolanaLiquidityOptions, SolanaLiquidityPlan, SolanaLiquidityResult, SolanaLiquiditySendOptions, SolanaRemoveLiquidityParams } from './types.js';
4
+ /**
5
+ * 添加流动性的计划(不签名、不发送):新建仓位(集中流动性的新 NFT / AMM 的 LP 代币),或往已有仓位追加。
6
+ * 返回预计的数量和按顺序执行的指令;只做读取,也可以当作报价
7
+ *
8
+ * ```ts
9
+ * // Raydium CLMM:价格区间按 token1 / token0(池子的方向),给一边的数量
10
+ * const plan = await buildAddLiquidity(client, owner, { protocol: 'raydium-clmm', pool, priceLower: 120, priceUpper: 180, amount0Formatted: '1' })
11
+ * plan.amount1Formatted // 需要的另一种代币
12
+ * plan.steps // [{ kind: 'setup', instructions }, { kind: 'add', instructions }];plan.signers 是新仓位 NFT 的临时密钥
13
+ * ```
14
+ */
15
+ export declare function buildAddLiquidity(client: SolanaClient, owner: string, params: SolanaAddLiquidityParams, options?: SolanaLiquidityOptions): Promise<SolanaLiquidityPlan>;
16
+ /** 移除流动性的计划(不签名、不发送):按比例或指定数量移除;集中流动性同时领取手续费和挖矿奖励 */
17
+ export declare function buildRemoveLiquidity(client: SolanaClient, owner: string, params: SolanaRemoveLiquidityParams, options?: SolanaLiquidityOptions): Promise<SolanaLiquidityPlan>;
18
+ /** 只领取集中流动性仓位的手续费和挖矿奖励(不动流动性)的计划 */
19
+ export declare function buildCollectFees(client: SolanaClient, owner: string, params: SolanaCollectFeesParams, options?: SolanaLiquidityOptions): Promise<SolanaLiquidityPlan>;
20
+ /**
21
+ * 添加流动性:构建计划后用 from 签名发送(钱包同 /write 的 batchCall:私钥、Keypair、Wallet Standard 钱包等)。
22
+ * 准备工作(创建代币账户、初始化 tick 数组、包装 SOL)和主指令能放进同一笔交易时合并成一笔
23
+ *
24
+ * ```ts
25
+ * const { status, plan } = await addLiquidity(client, secretKey, { protocol: 'orca-whirlpool', pool, fullRange: true, amount0Formatted: '0.5' })
26
+ * plan.positionMint // 新仓位的 NFT
27
+ * ```
28
+ */
29
+ export declare function addLiquidity(client: SolanaClient, from: SignerInput, params: SolanaAddLiquidityParams, options?: SolanaLiquiditySendOptions): Promise<SolanaLiquidityResult>;
30
+ /** 移除流动性:构建计划后用 from 签名发送 */
31
+ export declare function removeLiquidity(client: SolanaClient, from: SignerInput, params: SolanaRemoveLiquidityParams, options?: SolanaLiquiditySendOptions): Promise<SolanaLiquidityResult>;
32
+ /** 领取集中流动性仓位的手续费和挖矿奖励 */
33
+ export declare function collectFees(client: SolanaClient, from: SignerInput, params: SolanaCollectFeesParams, options?: SolanaLiquiditySendOptions): Promise<SolanaLiquidityResult>;
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/liquidity/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAShD,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAKpE,OAAO,KAAK,EACV,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAI1B,2BAA2B,EAC5B,MAAM,YAAY,CAAA;AAUnB;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMjL;AAED,qDAAqD;AACrD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,2BAA2B,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMvL;AAED,oCAAoC;AACpC,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAM/K;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,wBAAwB,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAMtL;AAED,6BAA6B;AAC7B,wBAAsB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,2BAA2B,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAG5L;AAED,yBAAyB;AACzB,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,GAAE,0BAA+B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAGpL"}
@@ -0,0 +1,157 @@
1
+ import { getAssociatedTokenAddress } from '../address.js';
2
+ import { NATIVE_MINT, TOKEN_PROGRAM_ID } from '../constants.js';
3
+ import { parseTokenAccount } from '../layout.js';
4
+ import { batchCall } from '../write/batch.js';
5
+ import { MAX_COMPUTE_UNITS, setComputeUnitLimit, setComputeUnitPrice } from '../write/instructions.js';
6
+ import { PACKET_DATA_SIZE, compileMessage, transactionSize } from '../write/transaction.js';
7
+ import { resolveSigner } from '../write/signer.js';
8
+ import { ammAdd, ammRemove } from './amm.js';
9
+ import { createCtx } from './common.js';
10
+ import { orcaAdd, orcaRemove } from './orca.js';
11
+ import { raydiumAdd, raydiumRemove } from './raydiumClmm.js';
12
+ function protocolOf(params) {
13
+ const protocol = 'position' in params ? params.position.protocol : params.protocol;
14
+ if (protocol !== 'raydium-clmm' && protocol !== 'orca-whirlpool' && protocol !== 'raydium-amm' && protocol !== 'raydium-cpmm') {
15
+ throw new Error(`Unknown LP protocol: ${String(protocol)}`);
16
+ }
17
+ return protocol;
18
+ }
19
+ /**
20
+ * 添加流动性的计划(不签名、不发送):新建仓位(集中流动性的新 NFT / AMM 的 LP 代币),或往已有仓位追加。
21
+ * 返回预计的数量和按顺序执行的指令;只做读取,也可以当作报价
22
+ *
23
+ * ```ts
24
+ * // Raydium CLMM:价格区间按 token1 / token0(池子的方向),给一边的数量
25
+ * const plan = await buildAddLiquidity(client, owner, { protocol: 'raydium-clmm', pool, priceLower: 120, priceUpper: 180, amount0Formatted: '1' })
26
+ * plan.amount1Formatted // 需要的另一种代币
27
+ * plan.steps // [{ kind: 'setup', instructions }, { kind: 'add', instructions }];plan.signers 是新仓位 NFT 的临时密钥
28
+ * ```
29
+ */
30
+ export async function buildAddLiquidity(client, owner, params, options = {}) {
31
+ const ctx = createCtx(client, owner, options);
32
+ const protocol = protocolOf(params);
33
+ if (protocol === 'raydium-clmm')
34
+ return raydiumAdd(ctx, params);
35
+ if (protocol === 'orca-whirlpool')
36
+ return orcaAdd(ctx, params);
37
+ return ammAdd(ctx, protocol, params);
38
+ }
39
+ /** 移除流动性的计划(不签名、不发送):按比例或指定数量移除;集中流动性同时领取手续费和挖矿奖励 */
40
+ export async function buildRemoveLiquidity(client, owner, params, options = {}) {
41
+ const ctx = createCtx(client, owner, options);
42
+ const protocol = protocolOf(params);
43
+ if (protocol === 'raydium-clmm')
44
+ return raydiumRemove(ctx, params);
45
+ if (protocol === 'orca-whirlpool')
46
+ return orcaRemove(ctx, params);
47
+ return ammRemove(ctx, protocol, params);
48
+ }
49
+ /** 只领取集中流动性仓位的手续费和挖矿奖励(不动流动性)的计划 */
50
+ export async function buildCollectFees(client, owner, params, options = {}) {
51
+ const ctx = createCtx(client, owner, options);
52
+ const protocol = protocolOf(params);
53
+ if (protocol === 'raydium-clmm')
54
+ return raydiumRemove(ctx, { position: params.position }, true);
55
+ if (protocol === 'orca-whirlpool')
56
+ return orcaRemove(ctx, { position: params.position }, true);
57
+ throw new Error('Raydium AMM v4 / CPMM have no separate fees: they are part of the LP tokens, remove liquidity to get them');
58
+ }
59
+ /**
60
+ * 添加流动性:构建计划后用 from 签名发送(钱包同 /write 的 batchCall:私钥、Keypair、Wallet Standard 钱包等)。
61
+ * 准备工作(创建代币账户、初始化 tick 数组、包装 SOL)和主指令能放进同一笔交易时合并成一笔
62
+ *
63
+ * ```ts
64
+ * const { status, plan } = await addLiquidity(client, secretKey, { protocol: 'orca-whirlpool', pool, fullRange: true, amount0Formatted: '0.5' })
65
+ * plan.positionMint // 新仓位的 NFT
66
+ * ```
67
+ */
68
+ export async function addLiquidity(client, from, params, options = {}) {
69
+ const plan = await buildAddLiquidity(client, (await resolveSigner(from)).address, params, options);
70
+ if (options.checkBalance ?? true) {
71
+ await checkBalance(client, plan, options.signal);
72
+ }
73
+ return execute(client, from, plan, options);
74
+ }
75
+ /** 移除流动性:构建计划后用 from 签名发送 */
76
+ export async function removeLiquidity(client, from, params, options = {}) {
77
+ const plan = await buildRemoveLiquidity(client, (await resolveSigner(from)).address, params, options);
78
+ return execute(client, from, plan, options);
79
+ }
80
+ /** 领取集中流动性仓位的手续费和挖矿奖励 */
81
+ export async function collectFees(client, from, params, options = {}) {
82
+ const plan = await buildCollectFees(client, (await resolveSigner(from)).address, params, options);
83
+ return execute(client, from, plan, options);
84
+ }
85
+ /** 添加前检查余额:代币按预计数量;SOL 那一边按上限减去已有的 wSOL(只包装差额),不含手续费和租金 */
86
+ async function checkBalance(client, plan, signal) {
87
+ const needs = [];
88
+ for (const [token, amount, max, native] of [
89
+ [plan.token0, plan.amount0, plan.amount0Max, plan.native === 'token0'],
90
+ [plan.token1, plan.amount1, plan.amount1Max, plan.native === 'token1'],
91
+ ]) {
92
+ const need = native ? BigInt(max ?? amount) : BigInt(amount);
93
+ if (need > 0n) {
94
+ needs.push({ mint: token.mint, amount: need, native });
95
+ }
96
+ }
97
+ if (!needs.length) {
98
+ return;
99
+ }
100
+ const wsol = getAssociatedTokenAddress(plan.owner, NATIVE_MINT, TOKEN_PROGRAM_ID);
101
+ const [balances, [wsolAccount]] = await Promise.all([
102
+ // NATIVE_MINT 在 balances 里读的是原生 SOL(lamports)
103
+ client.balances(plan.owner, needs.map((n) => n.mint), { signal }),
104
+ needs.some((n) => n.mint === NATIVE_MINT) ? client.accounts([wsol], { signal }) : Promise.resolve([null]),
105
+ ]);
106
+ needs.forEach((n, i) => {
107
+ const b = balances[i];
108
+ if (!b?.success) {
109
+ return; // 读不到的不拦(模拟时也会失败)
110
+ }
111
+ let have = BigInt(b.balance);
112
+ if (n.mint === NATIVE_MINT && !n.native) {
113
+ // 不包装 SOL 时用的是 wSOL 账户里的代币余额(balances 对 NATIVE_MINT 读的是原生 SOL)
114
+ have = 0n;
115
+ }
116
+ if (n.mint === NATIVE_MINT && wsolAccount) {
117
+ try {
118
+ have += parseTokenAccount(wsolAccount.data).amount;
119
+ }
120
+ catch {
121
+ // 不是代币账户:只算原生 SOL
122
+ }
123
+ }
124
+ if (have < n.amount) {
125
+ throw new Error(`Insufficient balance of ${n.native ? 'SOL' : n.mint}: need ${n.amount}, have ${have}`);
126
+ }
127
+ });
128
+ }
129
+ async function execute(client, from, plan, options) {
130
+ const { steps } = plan;
131
+ const nftSigners = plan.signers.map((s) => s.secretKey);
132
+ // 准备工作和主指令能放进同一笔交易时作为一个调用发送(原子执行:主指令模拟失败时准备工作也不发);
133
+ // 放不下时分开发送(准备工作只有创建代币账户、初始化 tick 数组,SOL 的包装和解包都在主指令那一步)
134
+ const payer = (await resolveSigner(options.feePayer ?? from)).address;
135
+ const all = steps.flatMap((s) => s.instructions);
136
+ const probe = compileMessage(payer, [setComputeUnitLimit(MAX_COMPUTE_UNITS), setComputeUnitPrice(1n), ...all], '11111111111111111111111111111111');
137
+ const merged = steps.length > 1 && transactionSize(probe) <= PACKET_DATA_SIZE;
138
+ const groups = merged ? [steps.map((_, i) => i)] : steps.map((_, i) => [i]);
139
+ const main = steps.length - 1;
140
+ const kindOf = (i) => steps[i].kind;
141
+ const raw = await batchCall(client, groups.map((group) => ({
142
+ from,
143
+ instructions: group.flatMap((i) => steps[i].instructions),
144
+ // 新仓位 NFT 的 mint 要在主指令所在的交易里签名
145
+ signers: group.includes(main) ? nftSigners : [],
146
+ })), {
147
+ ...options,
148
+ mode: 'pack',
149
+ // 准备工作失败时不发主指令
150
+ continueOnError: false,
151
+ onUpdate: options.onUpdate ? (r) => groups[r.index].forEach((i) => options.onUpdate?.({ ...r, index: i, kind: kindOf(i) })) : undefined,
152
+ });
153
+ const results = groups.flatMap((group, g) => group.map((i) => ({ ...raw[g], index: i, kind: kindOf(i) })));
154
+ const last = results[main];
155
+ return { plan, results, status: last.status, signature: last.signature };
156
+ }
157
+ //# sourceMappingURL=index.js.map