pinpet-sdk 0.1.1
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 +674 -0
- package/dist/index.d.ts +342 -0
- package/dist/pinpet-sdk.cjs.js +50648 -0
- package/dist/pinpet-sdk.cjs.js.map +1 -0
- package/dist/pinpet-sdk.esm.js +39265 -0
- package/dist/pinpet-sdk.esm.js.map +1 -0
- package/dist/pinpet-sdk.js +39277 -0
- package/dist/pinpet-sdk.js.map +1 -0
- package/package.json +67 -0
- package/src/idl/pinpet.json +3511 -0
- package/src/index.js +43 -0
- package/src/modules/chain.js +1102 -0
- package/src/modules/close.js +0 -0
- package/src/modules/fast.js +431 -0
- package/src/modules/param.js +171 -0
- package/src/modules/simulator/buy.js_del +711 -0
- package/src/modules/simulator/buy_sell_token.js +300 -0
- package/src/modules/simulator/calcLiq.js +701 -0
- package/src/modules/simulator/long_shrot_stop.js +602 -0
- package/src/modules/simulator/sell.js_del +323 -0
- package/src/modules/simulator/stop_loss_utils.js +223 -0
- package/src/modules/simulator/utils.js +44 -0
- package/src/modules/simulator.js +133 -0
- package/src/modules/token.js +140 -0
- package/src/modules/trading.js +1087 -0
- package/src/sdk.js +370 -0
- package/src/types/index.d.ts +342 -0
- package/src/utils/constants.js +49 -0
- package/src/utils/curve_amm.js +884 -0
- package/src/utils/orderUtils.js +465 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
|
|
2
|
+
const CurveAMM = require('../../utils/curve_amm');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 计算代币买入时的流动性影响 Calculate liquidity impact for token buy operations
|
|
7
|
+
*
|
|
8
|
+
* 此函数分析买入操作对价格区间内流动性的影响,计算可用的自由流动性、锁定流动性,
|
|
9
|
+
* 并支持跳过指定订单(将其流动性视为可用)。适用于做多订单(up_orders)场景。
|
|
10
|
+
* This function analyzes the liquidity impact of buy operations within price ranges,
|
|
11
|
+
* calculates available free liquidity, locked liquidity, and supports skipping specific
|
|
12
|
+
* orders (treating their liquidity as available). Applicable for long orders (up_orders) scenarios.
|
|
13
|
+
*
|
|
14
|
+
* @param {bigint|string|number} price - 当前代币价格,作为计算起始价格 Current token price, used as calculation start price
|
|
15
|
+
* @param {bigint|string|number} buyTokenAmount - 购买的代币数量,目标买入数量 Amount of tokens to buy, target purchase amount
|
|
16
|
+
* @param {Array<Object>} orders - 订单数组,按 lock_lp_start_price 从小到大排序 Array of orders sorted by lock_lp_start_price (ascending):
|
|
17
|
+
* - order_type: {number} 订单类型(1=做多,2=做空) Order type (1=long, 2=short)
|
|
18
|
+
* - mint: {string} 代币地址 Token mint address
|
|
19
|
+
* - user: {string} 用户地址 User address
|
|
20
|
+
* - lock_lp_start_price: {string} LP锁定开始价格 LP lock start price (required)
|
|
21
|
+
* - lock_lp_end_price: {string} LP锁定结束价格 LP lock end price (required)
|
|
22
|
+
* - lock_lp_sol_amount: {number} 锁定的SOL数量 Locked SOL amount (required)
|
|
23
|
+
* - lock_lp_token_amount: {number} 锁定的代币数量 Locked token amount (required)
|
|
24
|
+
* - start_time: {number} 开始时间戳 Start timestamp
|
|
25
|
+
* - end_time: {number} 结束时间戳 End timestamp
|
|
26
|
+
* - margin_sol_amount: {number} 保证金SOL数量 Margin SOL amount
|
|
27
|
+
* - borrow_amount: {number} 借贷数量 Borrow amount
|
|
28
|
+
* - position_asset_amount: {number} 持仓资产数量 Position asset amount
|
|
29
|
+
* - borrow_fee: {number} 借贷费用 Borrow fee
|
|
30
|
+
* - order_pda: {string} 订单PDA地址 Order PDA address (required for passOrder matching)
|
|
31
|
+
* @param {number} onceMaxOrder - 一次处理的最大订单数,限制遍历范围 Maximum orders to process at once, limits traversal range
|
|
32
|
+
* @param {string|null} passOrder - 需要跳过的订单PDA地址字符串,当该值与订单的order_pda匹配时,跳过该订单并将其流动性计入自由流动性 Order PDA address string to skip, when this value matches an order's order_pda, skip that order and count its liquidity as free liquidity
|
|
33
|
+
*
|
|
34
|
+
* @returns {Object} 流动性计算结果对象,包含详细的流动性分析数据 Liquidity calculation result object with detailed liquidity analysis data:
|
|
35
|
+
*
|
|
36
|
+
* **自由流动性 Free Liquidity:**
|
|
37
|
+
* - free_lp_sol_amount_sum: {bigint} 可用自由流动性SOL总量,包含以下来源:1)价格间隙流动性 2)跳过订单的流动性 3)无限流动性(如有)
|
|
38
|
+
* Total available free liquidity SOL amount, includes: 1) price gap liquidity 2) skipped order liquidity 3) infinite liquidity (if any)
|
|
39
|
+
* - free_lp_token_amount_sum: {bigint} 可用自由流动性Token总量,与SOL对应,表示在不强平任何订单情况下可买到的最大代币数量
|
|
40
|
+
* Total available free liquidity token amount, corresponds to SOL, represents max tokens buyable without force closing any orders
|
|
41
|
+
*
|
|
42
|
+
* **锁定流动性 Locked Liquidity:**
|
|
43
|
+
* - lock_lp_sol_amount_sum: {bigint} 被锁定的流动性SOL总量,不包括跳过的订单,这部分流动性不可直接使用
|
|
44
|
+
* Total locked liquidity SOL amount, excludes skipped orders, this liquidity is not directly usable
|
|
45
|
+
* - lock_lp_token_amount_sum: {bigint} 被锁定的流动性Token总量,不包括跳过的订单,对应于锁定的SOL流动性
|
|
46
|
+
* Total locked liquidity token amount, excludes skipped orders, corresponds to locked SOL liquidity
|
|
47
|
+
*
|
|
48
|
+
* **流动性状态标识 Liquidity Status Indicators:**
|
|
49
|
+
* - has_infinite_lp: {boolean} 是否包含无限流动性,true表示订单链表已结束且计算了到最大价格(MAX_U128_PRICE)的流动性
|
|
50
|
+
* Whether includes infinite liquidity, true means order chain ended and liquidity to max price (MAX_U128_PRICE) was calculated
|
|
51
|
+
* - pass_order_id: {number} 被跳过的订单在数组中的索引位置,-1表示没有跳过任何订单,>=0表示跳过了对应索引的订单
|
|
52
|
+
* Index of skipped order in array, -1 means no order skipped, >=0 means order at that index was skipped
|
|
53
|
+
*
|
|
54
|
+
* **买入执行信息 Buy Execution Info:**
|
|
55
|
+
* - force_close_num: {number} 需要强平的订单数量,表示为了买到目标数量需要强制平仓多少个订单,0表示无需强平
|
|
56
|
+
* Number of orders that need to be force closed, indicates how many orders need force closure to buy target amount, 0 means no force closure needed
|
|
57
|
+
* - ideal_lp_sol_amount: {bigint} 理想SOL使用量,基于当前价格使用CurveAMM直接计算的理论最小SOL需求,不考虑流动性分布
|
|
58
|
+
* Ideal SOL usage, theoretical minimum SOL requirement calculated directly from current price using CurveAMM, ignores liquidity distribution
|
|
59
|
+
* - real_lp_sol_amount: {bigint} 实际SOL使用量,考虑真实流动性分布的精确SOL需求。0表示当前自由流动性不足以满足买入需求,需要强平更多订单
|
|
60
|
+
* Actual SOL usage, precise SOL requirement considering real liquidity distribution. 0 means current free liquidity insufficient for buy requirement, need to force close more orders
|
|
61
|
+
*
|
|
62
|
+
* @throws {Error} 参数验证错误:price、buyTokenAmount、orders、onceMaxOrder 参数无效 Parameter validation error: invalid price, buyTokenAmount, orders, or onceMaxOrder
|
|
63
|
+
* @throws {Error} 价格转换错误:无法将价格参数转换为 BigInt Price conversion error: cannot convert price parameters to BigInt
|
|
64
|
+
* @throws {Error} 流动性计算错误:CurveAMM 计算失败或数值转换错误 Liquidity calculation error: CurveAMM calculation failure or value conversion error
|
|
65
|
+
* @throws {Error} 间隙流动性计算失败:价格间隙流动性计算异常 Gap liquidity calculation failure: price gap liquidity calculation exception
|
|
66
|
+
* @throws {Error} 无限流动性计算失败:最大价格流动性计算异常 Infinite liquidity calculation failure: max price liquidity calculation exception
|
|
67
|
+
* @throws {Error} 订单数据格式错误:订单对象缺少必需字段 Order data format error: order object missing required fields
|
|
68
|
+
*/
|
|
69
|
+
function calcLiqTokenBuy(price, buyTokenAmount, orders, onceMaxOrder, passOrder = null) {
|
|
70
|
+
// 由于是买入操作 肯定拿的是 up_orders 方向的 订单 lock_lp_start_price < lock_lp_end_price
|
|
71
|
+
// 并且 lock_lp_start_price 在 orders 中是从小到大排序的
|
|
72
|
+
|
|
73
|
+
// 参数验证
|
|
74
|
+
if (!price && price !== 0) {
|
|
75
|
+
throw new Error('参数验证错误:price 参数不能为空 Parameter validation error: price cannot be null');
|
|
76
|
+
}
|
|
77
|
+
if (!buyTokenAmount && buyTokenAmount !== 0) {
|
|
78
|
+
throw new Error('参数验证错误:buyTokenAmount 参数不能为空 Parameter validation error: buyTokenAmount cannot be null');
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(orders)) {
|
|
81
|
+
throw new Error('参数验证错误:orders 必须是数组 Parameter validation error: orders must be an array');
|
|
82
|
+
}
|
|
83
|
+
if (!onceMaxOrder || onceMaxOrder <= 0) {
|
|
84
|
+
throw new Error('参数验证错误:onceMaxOrder 必须是正数 Parameter validation error: onceMaxOrder must be a positive number');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = {
|
|
88
|
+
free_lp_sol_amount_sum: 0n, // 间隙中可使用的sol流动性数量
|
|
89
|
+
free_lp_token_amount_sum: 0n, // 间隙中可使用的token流动性数量
|
|
90
|
+
lock_lp_sol_amount_sum: 0n,
|
|
91
|
+
lock_lp_token_amount_sum: 0n,
|
|
92
|
+
has_infinite_lp: false, // 是否包含无限流动性
|
|
93
|
+
pass_order_id: -1, // 跳过的订单索引
|
|
94
|
+
force_close_num: 0, // 强平订单数量
|
|
95
|
+
ideal_lp_sol_amount: 0n, // 理想情况下买到buyTokenAmount的数量, 理想情况下使用的SOL数量
|
|
96
|
+
real_lp_sol_amount: 0n, // 要买到buyTokenAmount的数量, 实际使用的SOL数量
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
let buyTokenAmountBigInt;
|
|
103
|
+
try {
|
|
104
|
+
buyTokenAmountBigInt = BigInt(buyTokenAmount);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new Error(`价格转换错误:无法将 buyTokenAmount 转换为 BigInt Price conversion error: Cannot convert buyTokenAmount to BigInt - ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 声明用于跟踪前一次自由流动性总量的变量
|
|
110
|
+
let prev_free_lp_sol_amount_sum;
|
|
111
|
+
|
|
112
|
+
//result.ideal_lp_token_amount_sum = buyTokenAmountBigInt;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const priceBigInt = BigInt(price);
|
|
116
|
+
[, result.ideal_lp_sol_amount] = CurveAMM.buyFromPriceWithTokenOutput(priceBigInt, buyTokenAmountBigInt);
|
|
117
|
+
// console.log(`理想计算: 当前价格=${priceBigInt}, 目标代币=${buyTokenAmountBigInt}, 理想SOL=${result.ideal_lp_sol_amount}`);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw new Error(`buy流动性计算错误:理想流动性计算失败 Liquidity calculation error: Ideal liquidity calculation failed - ${error.message}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
// orders 长度为0 时要单独计算
|
|
124
|
+
if (orders.length === 0) {
|
|
125
|
+
[result.free_lp_sol_amount_sum, result.free_lp_token_amount_sum] = CurveAMM.buyFromPriceToPrice(BigInt(price), CurveAMM.MAX_U128_PRICE);
|
|
126
|
+
result.has_infinite_lp = true;
|
|
127
|
+
result.real_lp_sol_amount = result.ideal_lp_sol_amount
|
|
128
|
+
return result
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
// 选择较小值进行遍历
|
|
135
|
+
const loopCount = Math.min(orders.length, onceMaxOrder);
|
|
136
|
+
|
|
137
|
+
let counti = 0;
|
|
138
|
+
for (let i = 0; i < loopCount; i++) {
|
|
139
|
+
const order = orders[i];
|
|
140
|
+
|
|
141
|
+
// 验证订单数据格式
|
|
142
|
+
if (!order) {
|
|
143
|
+
throw new Error(`订单数据格式错误:订单 ${i} 为空 Order data format error: Order ${i} is null`);
|
|
144
|
+
}
|
|
145
|
+
if (!order.lock_lp_start_price) {
|
|
146
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_start_price Order data format error: Order ${i} missing lock_lp_start_price`);
|
|
147
|
+
}
|
|
148
|
+
if (!order.lock_lp_end_price) {
|
|
149
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_end_price Order data format error: Order ${i} missing lock_lp_end_price`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
// 计算间隙流动性
|
|
154
|
+
let startPrice, endPrice;
|
|
155
|
+
try {
|
|
156
|
+
if (i === 0) {
|
|
157
|
+
// 第一个订单:使用当前价格到订单开始价格的间隙
|
|
158
|
+
startPrice = BigInt(price);
|
|
159
|
+
endPrice = BigInt(order.lock_lp_start_price);
|
|
160
|
+
} else {
|
|
161
|
+
// 后续订单:使用前一个订单结束价格到当前订单开始价格的间隙
|
|
162
|
+
startPrice = BigInt(orders[i - 1].lock_lp_end_price);
|
|
163
|
+
endPrice = BigInt(order.lock_lp_start_price);
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
throw new Error(`价格转换错误:无法转换订单 ${i} 的价格数据 Price conversion error: Cannot convert price data for order ${i} - ${error.message}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
// 如果存在价格间隙,计算自由流动性
|
|
171
|
+
if (endPrice > startPrice) {
|
|
172
|
+
try {
|
|
173
|
+
const gapLiquidity = CurveAMM.buyFromPriceToPrice(startPrice, endPrice);
|
|
174
|
+
if (gapLiquidity && Array.isArray(gapLiquidity) && gapLiquidity.length === 2) {
|
|
175
|
+
const [solAmount, tokenAmount] = gapLiquidity;
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
prev_free_lp_sol_amount_sum = result.free_lp_sol_amount_sum; // 上次的值
|
|
179
|
+
result.free_lp_sol_amount_sum += BigInt(solAmount);
|
|
180
|
+
result.free_lp_token_amount_sum += BigInt(tokenAmount);
|
|
181
|
+
// console.log(`间隙[${i}]: ${startPrice}→${endPrice}, 间隙SOL=${solAmount}, 间隙Token=${tokenAmount}, 累计自由Token=${result.free_lp_token_amount_sum}`);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
throw new Error(`流动性计算错误:无法转换间隙流动性数值 Liquidity calculation error: Cannot convert gap liquidity values - ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
// 计算实际使用的SOL数量 到能买到为止
|
|
188
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
189
|
+
if (result.free_lp_token_amount_sum > buyTokenAmountBigInt) {
|
|
190
|
+
// 这时间隙流动性已经够买入的了
|
|
191
|
+
// 计算最后精确需要买多少token
|
|
192
|
+
try {
|
|
193
|
+
const actualBuyAmount = buyTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(tokenAmount));
|
|
194
|
+
// console.log("actualBuyAmount",actualBuyAmount)
|
|
195
|
+
const [, preciseSol] = CurveAMM.buyFromPriceWithTokenOutput(startPrice, actualBuyAmount)
|
|
196
|
+
result.real_lp_sol_amount = prev_free_lp_sol_amount_sum + BigInt(preciseSol);
|
|
197
|
+
|
|
198
|
+
// console.log(`实际计算[${i}]: 自由流动性已足够, actualBuyAmount=${actualBuyAmount}, preciseSol=${preciseSol}, 实际SOL=${result.real_lp_sol_amount}`);
|
|
199
|
+
result.force_close_num = counti; // 强平订单数量
|
|
200
|
+
} catch (error) {
|
|
201
|
+
// console.log('错误详情:', error);
|
|
202
|
+
throw new Error(`流动性计算错误:精确SOL计算失败 Liquidity calculation error: Precise SOL calculation failed - ${error.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
} else {
|
|
208
|
+
throw new Error(`间隙流动性计算失败:返回数据格式错误 Gap liquidity calculation failure: Invalid return data format`);
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error.message.includes('间隙流动性计算失败') || error.message.includes('流动性计算错误')) {
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
throw new Error(`间隙流动性计算失败:${error.message} Gap liquidity calculation failure: ${error.message}`);
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 检查是否需要跳过该订单(passOrder 逻辑)
|
|
220
|
+
//const shouldSkipOrder = passOrder && typeof passOrder === 'string' && order.order_pda === passOrder;
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
if (passOrder == order.order_pda) {
|
|
224
|
+
|
|
225
|
+
// 将跳过订单的流动性加到自由流动性中
|
|
226
|
+
try {
|
|
227
|
+
if (order.lock_lp_sol_amount === undefined || order.lock_lp_sol_amount === null) {
|
|
228
|
+
throw new Error(`订单数据格式错误:跳过订单 ${i} 缺少 lock_lp_sol_amount Order data format error: Skipped order ${i} missing lock_lp_sol_amount`);
|
|
229
|
+
}
|
|
230
|
+
if (order.lock_lp_token_amount === undefined || order.lock_lp_token_amount === null) {
|
|
231
|
+
throw new Error(`订单数据格式错误:跳过订单 ${i} 缺少 lock_lp_token_amount Order data format error: Skipped order ${i} missing lock_lp_token_amount`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const prevFreeSolSum = result.free_lp_sol_amount_sum; // 保存之前的值用于计算
|
|
235
|
+
result.free_lp_sol_amount_sum += BigInt(order.lock_lp_sol_amount);
|
|
236
|
+
result.free_lp_token_amount_sum += BigInt(order.lock_lp_token_amount);
|
|
237
|
+
|
|
238
|
+
result.pass_order_id = i;
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
// 检查跳过订单后的自由流动性是否已满足买入需求
|
|
242
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
243
|
+
if (result.free_lp_token_amount_sum >= buyTokenAmountBigInt) {
|
|
244
|
+
// 自由流动性已经够买入需求了
|
|
245
|
+
try {
|
|
246
|
+
//const remainingToken = result.free_lp_token_amount_sum - buyTokenAmountBigInt;
|
|
247
|
+
// 从当前价格开始计算需要多少SOL来买到精确的token数量
|
|
248
|
+
const targetPrice = i === 0 ? BigInt(price) : BigInt(orders[i - 1].lock_lp_end_price);
|
|
249
|
+
const actualBuyAmount = buyTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(order.lock_lp_token_amount));
|
|
250
|
+
const [, preciseSol] = CurveAMM.buyFromPriceWithTokenOutput(targetPrice, actualBuyAmount);
|
|
251
|
+
result.real_lp_sol_amount = prevFreeSolSum + BigInt(preciseSol);
|
|
252
|
+
// console.log(`实际计算[${i}]: 跳过订单后足够, targetPrice=${targetPrice}, preciseSol=${preciseSol}, 实际SOL=${result.real_lp_sol_amount}`);
|
|
253
|
+
result.force_close_num = counti;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
throw new Error(`流动性计算错误:跳过订单后精确SOL计算失败 Liquidity calculation error: Precise SOL calculation failed after skipping order - ${error.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
} catch (error) {
|
|
261
|
+
if (error.message.includes('订单数据格式错误') || error.message.includes('流动性计算错误')) {
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
throw new Error(`流动性计算错误:无法处理跳过订单 ${i} 的流动性 Liquidity calculation error: Cannot process skipped order ${i} liquidity - ${error.message}`);
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
// 累加锁定的流动性(正常情况)
|
|
268
|
+
try {
|
|
269
|
+
if (order.lock_lp_sol_amount === undefined || order.lock_lp_sol_amount === null) {
|
|
270
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_sol_amount Order data format error: Order ${i} missing lock_lp_sol_amount`);
|
|
271
|
+
}
|
|
272
|
+
if (order.lock_lp_token_amount === undefined || order.lock_lp_token_amount === null) {
|
|
273
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_token_amount Order data format error: Order ${i} missing lock_lp_token_amount`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
result.lock_lp_sol_amount_sum += BigInt(order.lock_lp_sol_amount);
|
|
277
|
+
result.lock_lp_token_amount_sum += BigInt(order.lock_lp_token_amount);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (error.message.includes('订单数据格式错误')) {
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
throw new Error(`流动性计算错误:无法累加订单 ${i} 的锁定流动性 Liquidity calculation error: Cannot accumulate locked liquidity for order ${i} - ${error.message}`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
counti += 1;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// 如果遍历的订单数小于等于onceMaxOrder,说明链表结束,需要计算无限流动性
|
|
294
|
+
if (orders.length <= onceMaxOrder && orders.length > 0) {
|
|
295
|
+
|
|
296
|
+
const lastOrder = orders[orders.length - 1];
|
|
297
|
+
if (!lastOrder || !lastOrder.lock_lp_end_price) {
|
|
298
|
+
throw new Error(`订单数据格式错误:最后一个订单缺少 lock_lp_end_price Order data format error: Last order missing lock_lp_end_price`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let lastEndPrice, maxPrice;
|
|
302
|
+
try {
|
|
303
|
+
lastEndPrice = BigInt(lastOrder.lock_lp_end_price);
|
|
304
|
+
maxPrice = CurveAMM.MAX_U128_PRICE;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw new Error(`价格转换错误:无法转换最后订单价格或最大价格 Price conversion error: Cannot convert last order price or max price - ${error.message}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
if (maxPrice > lastEndPrice) {
|
|
311
|
+
try {
|
|
312
|
+
const infiniteLiquidity = CurveAMM.buyFromPriceToPrice(lastEndPrice, maxPrice);
|
|
313
|
+
if (infiniteLiquidity && Array.isArray(infiniteLiquidity) && infiniteLiquidity.length === 2) {
|
|
314
|
+
const [solAmount, tokenAmount] = infiniteLiquidity;
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
result.free_lp_sol_amount_sum += BigInt(solAmount);
|
|
318
|
+
result.free_lp_token_amount_sum += BigInt(tokenAmount);
|
|
319
|
+
result.has_infinite_lp = true;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
throw new Error(`流动性计算错误:无法转换无限流动性数值 Liquidity calculation error: Cannot convert infinite liquidity values - ${error.message}`);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 进入无限流动性后 也要 , 计算实际使用的SOL数量 到能买到为止
|
|
325
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
326
|
+
if (result.free_lp_token_amount_sum > buyTokenAmountBigInt) {
|
|
327
|
+
// 这时间隙流动性已经够买入的了
|
|
328
|
+
// 计算最后精确需要买多少token
|
|
329
|
+
try {
|
|
330
|
+
const actualBuyAmount = buyTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(tokenAmount));
|
|
331
|
+
const [, preciseSol] = CurveAMM.buyFromPriceWithTokenOutput(lastEndPrice, actualBuyAmount)
|
|
332
|
+
result.real_lp_sol_amount += BigInt(preciseSol);
|
|
333
|
+
result.force_close_num = counti; // 强平订单数量
|
|
334
|
+
} catch (error) {
|
|
335
|
+
throw new Error(`流动性计算错误:无限流动性精确SOL计算失败 Liquidity calculation error: Infinite liquidity precise SOL calculation failed - ${error.message}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
} else {
|
|
341
|
+
throw new Error(`无限流动性计算失败:返回数据格式错误 Infinite liquidity calculation failure: Invalid return data format`);
|
|
342
|
+
}
|
|
343
|
+
} catch (error) {
|
|
344
|
+
if (error.message.includes('无限流动性计算失败') || error.message.includes('流动性计算错误') || error.message.includes('订单数据格式错误') || error.message.includes('价格转换错误')) {
|
|
345
|
+
throw error;
|
|
346
|
+
}
|
|
347
|
+
throw new Error(`无限流动性计算失败:${error.message} Infinite liquidity calculation failure: ${error.message}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return result;
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* 计算代币卖出时的流动性影响 Calculate liquidity impact for token sell operations
|
|
361
|
+
*
|
|
362
|
+
* 此函数分析卖出操作对价格区间内流动性的影响,计算可用的自由流动性、锁定流动性,
|
|
363
|
+
* 并支持跳过指定订单(将其流动性视为可用)。适用于做空订单(down_orders)场景。
|
|
364
|
+
* This function analyzes the liquidity impact of sell operations within price ranges,
|
|
365
|
+
* calculates available free liquidity, locked liquidity, and supports skipping specific
|
|
366
|
+
* orders (treating their liquidity as available). Applicable for short orders (down_orders) scenarios.
|
|
367
|
+
*
|
|
368
|
+
* @param {bigint|string|number} price - 当前代币价格,作为计算起始价格 Current token price, used as calculation start price
|
|
369
|
+
* @param {bigint|string|number} sellTokenAmount - 卖出的代币数量,目标卖出数量 Amount of tokens to sell, target sell amount
|
|
370
|
+
* @param {Array<Object>} orders - 订单数组,按 lock_lp_start_price 从大到小排序 Array of orders sorted by lock_lp_start_price (descending):
|
|
371
|
+
* - order_type: {number} 订单类型(1=做多,2=做空) Order type (1=long, 2=short)
|
|
372
|
+
* - mint: {string} 代币地址 Token mint address
|
|
373
|
+
* - user: {string} 用户地址 User address
|
|
374
|
+
* - lock_lp_start_price: {string} LP锁定开始价格(高价) LP lock start price (high price) (required)
|
|
375
|
+
* - lock_lp_end_price: {string} LP锁定结束价格(低价) LP lock end price (low price) (required)
|
|
376
|
+
* - lock_lp_sol_amount: {number} 锁定的SOL数量 Locked SOL amount (required)
|
|
377
|
+
* - lock_lp_token_amount: {number} 锁定的代币数量 Locked token amount (required)
|
|
378
|
+
* - start_time: {number} 开始时间戳 Start timestamp
|
|
379
|
+
* - end_time: {number} 结束时间戳 End timestamp
|
|
380
|
+
* - margin_sol_amount: {number} 保证金SOL数量 Margin SOL amount
|
|
381
|
+
* - borrow_amount: {number} 借贷数量 Borrow amount
|
|
382
|
+
* - position_asset_amount: {number} 持仓资产数量 Position asset amount
|
|
383
|
+
* - borrow_fee: {number} 借贷费用 Borrow fee
|
|
384
|
+
* - order_pda: {string} 订单PDA地址 Order PDA address (required for passOrder matching)
|
|
385
|
+
* @param {number} onceMaxOrder - 一次处理的最大订单数,限制遍历范围 Maximum orders to process at once, limits traversal range
|
|
386
|
+
* @param {string|null} passOrder - 需要跳过的订单PDA地址字符串,当该值与订单的order_pda匹配时,跳过该订单并将其流动性计入自由流动性 Order PDA address string to skip, when this value matches an order's order_pda, skip that order and count its liquidity as free liquidity
|
|
387
|
+
*
|
|
388
|
+
* @returns {Object} 流动性计算结果对象,包含详细的流动性分析数据 Liquidity calculation result object with detailed liquidity analysis data:
|
|
389
|
+
*
|
|
390
|
+
* **自由流动性 Free Liquidity:**
|
|
391
|
+
* - free_lp_sol_amount_sum: {bigint} 可用自由流动性SOL总量,表示卖出时能获得的SOL,包含:1)价格间隙流动性 2)跳过订单的流动性 3)无限流动性(如有)
|
|
392
|
+
* Total available free liquidity SOL amount, represents SOL obtainable from selling, includes: 1) price gap liquidity 2) skipped order liquidity 3) infinite liquidity (if any)
|
|
393
|
+
* - free_lp_token_amount_sum: {bigint} 可用自由流动性Token总量,表示在不强平任何订单情况下可卖出的最大代币数量
|
|
394
|
+
* Total available free liquidity token amount, represents max tokens sellable without force closing any orders
|
|
395
|
+
*
|
|
396
|
+
* **锁定流动性 Locked Liquidity:**
|
|
397
|
+
* - lock_lp_sol_amount_sum: {bigint} 被锁定的流动性SOL总量,不包括跳过的订单,这部分流动性不可直接使用
|
|
398
|
+
* Total locked liquidity SOL amount, excludes skipped orders, this liquidity is not directly usable
|
|
399
|
+
* - lock_lp_token_amount_sum: {bigint} 被锁定的流动性Token总量,不包括跳过的订单,对应于锁定的SOL流动性
|
|
400
|
+
* Total locked liquidity token amount, excludes skipped orders, corresponds to locked SOL liquidity
|
|
401
|
+
*
|
|
402
|
+
* **流动性状态标识 Liquidity Status Indicators:**
|
|
403
|
+
* - has_infinite_lp: {boolean} 是否包含无限流动性,true表示订单链表已结束且计算了到最小价格(MIN_U128_PRICE)的流动性
|
|
404
|
+
* Whether includes infinite liquidity, true means order chain ended and liquidity to min price (MIN_U128_PRICE) was calculated
|
|
405
|
+
* - pass_order_id: {number} 被跳过的订单在数组中的索引位置,-1表示没有跳过任何订单,>=0表示跳过了对应索引的订单
|
|
406
|
+
* Index of skipped order in array, -1 means no order skipped, >=0 means order at that index was skipped
|
|
407
|
+
*
|
|
408
|
+
* **卖出执行信息 Sell Execution Info:**
|
|
409
|
+
* - force_close_num: {number} 需要强平的订单数量,表示为了卖出目标数量需要强制平仓多少个订单,0表示无需强平
|
|
410
|
+
* Number of orders that need to be force closed, indicates how many orders need force closure to sell target amount, 0 means no force closure needed
|
|
411
|
+
* - ideal_lp_sol_amount: {bigint} 理想SOL获得量,基于当前价格使用CurveAMM直接计算的理论最大SOL收益,不考虑流动性分布
|
|
412
|
+
* Ideal SOL amount obtainable, theoretical maximum SOL revenue calculated directly from current price using CurveAMM, ignores liquidity distribution
|
|
413
|
+
* - real_lp_sol_amount: {bigint} 实际SOL获得量,考虑真实流动性分布的精确SOL收益。0表示当前自由流动性不足以满足卖出需求,需要强平更多订单
|
|
414
|
+
* Actual SOL amount obtainable, precise SOL revenue considering real liquidity distribution. 0 means current free liquidity insufficient for sell requirement, need to force close more orders
|
|
415
|
+
*
|
|
416
|
+
* @throws {Error} 参数验证错误:price、sellTokenAmount、orders、onceMaxOrder 参数无效 Parameter validation error: invalid price, sellTokenAmount, orders, or onceMaxOrder
|
|
417
|
+
* @throws {Error} 价格转换错误:无法将价格参数转换为 BigInt Price conversion error: cannot convert price parameters to BigInt
|
|
418
|
+
* @throws {Error} 流动性计算错误:CurveAMM 计算失败或数值转换错误 Liquidity calculation error: CurveAMM calculation failure or value conversion error
|
|
419
|
+
* @throws {Error} 间隙流动性计算失败:价格间隙流动性计算异常 Gap liquidity calculation failure: price gap liquidity calculation exception
|
|
420
|
+
* @throws {Error} 无限流动性计算失败:最小价格流动性计算异常 Infinite liquidity calculation failure: min price liquidity calculation exception
|
|
421
|
+
* @throws {Error} 订单数据格式错误:订单对象缺少必需字段 Order data format error: order object missing required fields
|
|
422
|
+
*/
|
|
423
|
+
function calcLiqTokenSell(price, sellTokenAmount, orders, onceMaxOrder, passOrder = null) {
|
|
424
|
+
// 由于是卖出操作 肯定拿的是 down_orders 方向的 订单 lock_lp_start_price > lock_lp_end_price
|
|
425
|
+
// 并且 lock_lp_start_price 在 orders 中是从大到小排序的
|
|
426
|
+
|
|
427
|
+
// 参数验证
|
|
428
|
+
if (!price && price !== 0) {
|
|
429
|
+
throw new Error('参数验证错误:price 参数不能为空 Parameter validation error: price cannot be null');
|
|
430
|
+
}
|
|
431
|
+
if (!sellTokenAmount && sellTokenAmount !== 0) {
|
|
432
|
+
throw new Error('参数验证错误:sellTokenAmount 参数不能为空 Parameter validation error: sellTokenAmount cannot be null');
|
|
433
|
+
}
|
|
434
|
+
if (!Array.isArray(orders)) {
|
|
435
|
+
throw new Error('参数验证错误:orders 必须是数组 Parameter validation error: orders must be an array');
|
|
436
|
+
}
|
|
437
|
+
if (!onceMaxOrder || onceMaxOrder <= 0) {
|
|
438
|
+
throw new Error('参数验证错误:onceMaxOrder 必须是正数 Parameter validation error: onceMaxOrder must be a positive number');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const result = {
|
|
442
|
+
free_lp_sol_amount_sum: 0n, // 间隙中可使用的sol流动性数量
|
|
443
|
+
free_lp_token_amount_sum: 0n, // 间隙中可使用的token流动性数量
|
|
444
|
+
lock_lp_sol_amount_sum: 0n,
|
|
445
|
+
lock_lp_token_amount_sum: 0n,
|
|
446
|
+
has_infinite_lp: false, // 是否包含无限流动性
|
|
447
|
+
pass_order_id: -1, // 跳过的订单索引
|
|
448
|
+
force_close_num: 0, // 强平订单数量
|
|
449
|
+
ideal_lp_sol_amount: 0n, // 理想情况下卖出sellTokenAmount能获得的SOL数量
|
|
450
|
+
real_lp_sol_amount: 0n, // 实际卖出sellTokenAmount能获得的SOL数量
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
let sellTokenAmountBigInt;
|
|
454
|
+
try {
|
|
455
|
+
sellTokenAmountBigInt = BigInt(sellTokenAmount);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
throw new Error(`价格转换错误:无法将 sellTokenAmount 转换为 BigInt Price conversion error: Cannot convert sellTokenAmount to BigInt - ${error.message}`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// 声明用于跟踪前一次自由流动性总量的变量
|
|
461
|
+
let prev_free_lp_sol_amount_sum;
|
|
462
|
+
|
|
463
|
+
// 计算理想情况下卖出能获得的SOL数量
|
|
464
|
+
try {
|
|
465
|
+
const priceBigInt = BigInt(price);
|
|
466
|
+
[, result.ideal_lp_sol_amount] = CurveAMM.sellFromPriceWithTokenInput(priceBigInt, sellTokenAmountBigInt);
|
|
467
|
+
// console.log(`理想计算: 当前价格=${priceBigInt}, 卖出代币=${sellTokenAmountBigInt}, 理想SOL=${result.ideal_lp_sol_amount}`);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
throw new Error(`sell流动性计算错误:理想流动性计算失败 Liquidity calculation error: Ideal liquidity calculation failed - ${error.message}`);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// orders 长度为0 时要单独计算
|
|
473
|
+
if (orders.length === 0) {
|
|
474
|
+
[result.free_lp_token_amount_sum, result.free_lp_sol_amount_sum] = CurveAMM.sellFromPriceToPrice(BigInt(price), CurveAMM.MIN_U128_PRICE);
|
|
475
|
+
result.has_infinite_lp = true;
|
|
476
|
+
result.real_lp_sol_amount = result.ideal_lp_sol_amount
|
|
477
|
+
return result
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
// 选择较小值进行遍历
|
|
484
|
+
const loopCount = Math.min(orders.length, onceMaxOrder);
|
|
485
|
+
|
|
486
|
+
let counti = 0;
|
|
487
|
+
for (let i = 0; i < loopCount; i++) {
|
|
488
|
+
const order = orders[i];
|
|
489
|
+
// console.log(`处理卖出订单[${i}]: 累计自由Token=${result.free_lp_token_amount_sum}, 目标=${sellTokenAmountBigInt}, 需要=${sellTokenAmountBigInt > result.free_lp_token_amount_sum}`);
|
|
490
|
+
|
|
491
|
+
// 验证订单数据格式
|
|
492
|
+
if (!order) {
|
|
493
|
+
throw new Error(`订单数据格式错误:订单 ${i} 为空 Order data format error: Order ${i} is null`);
|
|
494
|
+
}
|
|
495
|
+
if (!order.lock_lp_start_price) {
|
|
496
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_start_price Order data format error: Order ${i} missing lock_lp_start_price`);
|
|
497
|
+
}
|
|
498
|
+
if (!order.lock_lp_end_price) {
|
|
499
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_end_price Order data format error: Order ${i} missing lock_lp_end_price`);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
// 计算间隙流动性(卖出方向:从高价到低价)
|
|
504
|
+
let startPrice, endPrice;
|
|
505
|
+
try {
|
|
506
|
+
if (i === 0) {
|
|
507
|
+
// 第一个订单:从当前价格(高)到订单开始价格(低)的间隙
|
|
508
|
+
startPrice = BigInt(price);
|
|
509
|
+
endPrice = BigInt(order.lock_lp_start_price);
|
|
510
|
+
} else {
|
|
511
|
+
// 后续订单:从前一个订单结束价格(高)到当前订单开始价格(低)的间隙
|
|
512
|
+
startPrice = BigInt(orders[i - 1].lock_lp_end_price);
|
|
513
|
+
endPrice = BigInt(order.lock_lp_start_price);
|
|
514
|
+
}
|
|
515
|
+
} catch (error) {
|
|
516
|
+
throw new Error(`价格转换错误:无法转换订单 ${i} 的价格数据 Price conversion error: Cannot convert price data for order ${i} - ${error.message}`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
// 如果存在价格间隙(卖出时startPrice应该大于endPrice)
|
|
521
|
+
if (startPrice > endPrice) {
|
|
522
|
+
try {
|
|
523
|
+
const gapLiquidity = CurveAMM.sellFromPriceToPrice(startPrice, endPrice);
|
|
524
|
+
if (gapLiquidity && Array.isArray(gapLiquidity) && gapLiquidity.length === 2) {
|
|
525
|
+
const [tokenAmount, solAmount] = gapLiquidity;
|
|
526
|
+
|
|
527
|
+
try {
|
|
528
|
+
prev_free_lp_sol_amount_sum = result.free_lp_sol_amount_sum; // 上次的值
|
|
529
|
+
result.free_lp_sol_amount_sum += BigInt(solAmount);
|
|
530
|
+
result.free_lp_token_amount_sum += BigInt(tokenAmount);
|
|
531
|
+
// console.log(`卖出间隙[${i}]: ${startPrice}→${endPrice}, 间隙Token=${tokenAmount}, 间隙SOL=${solAmount}, 累计自由Token=${result.free_lp_token_amount_sum}`);
|
|
532
|
+
} catch (error) {
|
|
533
|
+
throw new Error(`流动性计算错误:无法转换间隙流动性数值 Liquidity calculation error: Cannot convert gap liquidity values - ${error.message}`);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// 计算实际获得的SOL数量 到能卖出为止
|
|
537
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
538
|
+
if (result.free_lp_token_amount_sum >= sellTokenAmountBigInt) {
|
|
539
|
+
// 这时间隙流动性已经够卖出的了
|
|
540
|
+
// 计算精确能获得多少SOL
|
|
541
|
+
try {
|
|
542
|
+
const actualSellAmount = sellTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(tokenAmount));
|
|
543
|
+
const [, preciseSol] = CurveAMM.sellFromPriceWithTokenInput(startPrice, actualSellAmount);
|
|
544
|
+
result.real_lp_sol_amount = prev_free_lp_sol_amount_sum + preciseSol;
|
|
545
|
+
// console.log(`卖出实际计算[${i}]: 自由流动性已足够, actualSellAmount=${actualSellAmount}, preciseSol=${preciseSol}, 实际SOL=${result.real_lp_sol_amount}`);
|
|
546
|
+
result.force_close_num = counti; // 强平订单数量
|
|
547
|
+
} catch (error) {
|
|
548
|
+
throw new Error(`流动性计算错误:精确SOL计算失败 Liquidity calculation error: Precise SOL calculation failed - ${error.message}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
} else {
|
|
554
|
+
throw new Error(`间隙流动性计算失败:返回数据格式错误 Gap liquidity calculation failure: Invalid return data format`);
|
|
555
|
+
}
|
|
556
|
+
} catch (error) {
|
|
557
|
+
if (error.message.includes('间隙流动性计算失败') || error.message.includes('流动性计算错误')) {
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
throw new Error(`间隙流动性计算失败:${error.message} Gap liquidity calculation failure: ${error.message}`);
|
|
561
|
+
}
|
|
562
|
+
} else {
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// 检查是否需要跳过该订单(passOrder 逻辑)
|
|
566
|
+
|
|
567
|
+
if (passOrder == order.order_pda) {
|
|
568
|
+
|
|
569
|
+
// 将跳过订单的流动性加到自由流动性中
|
|
570
|
+
try {
|
|
571
|
+
if (order.lock_lp_sol_amount === undefined || order.lock_lp_sol_amount === null) {
|
|
572
|
+
throw new Error(`订单数据格式错误:跳过订单 ${i} 缺少 lock_lp_sol_amount Order data format error: Skipped order ${i} missing lock_lp_sol_amount`);
|
|
573
|
+
}
|
|
574
|
+
if (order.lock_lp_token_amount === undefined || order.lock_lp_token_amount === null) {
|
|
575
|
+
throw new Error(`订单数据格式错误:跳过订单 ${i} 缺少 lock_lp_token_amount Order data format error: Skipped order ${i} missing lock_lp_token_amount`);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const prevFreeSolSum = result.free_lp_sol_amount_sum; // 保存之前的值用于计算
|
|
579
|
+
result.free_lp_sol_amount_sum += BigInt(order.lock_lp_sol_amount);
|
|
580
|
+
result.free_lp_token_amount_sum += BigInt(order.lock_lp_token_amount);
|
|
581
|
+
|
|
582
|
+
result.pass_order_id = i;
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
// 检查跳过订单后的自由流动性是否已满足卖出需求
|
|
586
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
587
|
+
if (result.free_lp_token_amount_sum >= sellTokenAmountBigInt) {
|
|
588
|
+
// 自由流动性已经够卖出需求了
|
|
589
|
+
try {
|
|
590
|
+
// 计算精确能获得多少SOL
|
|
591
|
+
const targetPrice = i === 0 ? BigInt(price) : BigInt(orders[i - 1].lock_lp_end_price);
|
|
592
|
+
const actualSellAmount = sellTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(order.lock_lp_token_amount));
|
|
593
|
+
const [, preciseSol] = CurveAMM.sellFromPriceWithTokenInput(targetPrice, actualSellAmount);
|
|
594
|
+
result.real_lp_sol_amount = prevFreeSolSum + preciseSol;
|
|
595
|
+
result.force_close_num = counti;
|
|
596
|
+
} catch (error) {
|
|
597
|
+
throw new Error(`流动性计算错误:跳过订单后精确SOL计算失败 Liquidity calculation error: Precise SOL calculation failed after skipping order - ${error.message}`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
} catch (error) {
|
|
603
|
+
if (error.message.includes('订单数据格式错误') || error.message.includes('流动性计算错误')) {
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
throw new Error(`流动性计算错误:无法处理跳过订单 ${i} 的流动性 Liquidity calculation error: Cannot process skipped order ${i} liquidity - ${error.message}`);
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
// 累加锁定的流动性(正常情况)
|
|
610
|
+
try {
|
|
611
|
+
if (order.lock_lp_sol_amount === undefined || order.lock_lp_sol_amount === null) {
|
|
612
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_sol_amount Order data format error: Order ${i} missing lock_lp_sol_amount`);
|
|
613
|
+
}
|
|
614
|
+
if (order.lock_lp_token_amount === undefined || order.lock_lp_token_amount === null) {
|
|
615
|
+
throw new Error(`订单数据格式错误:订单 ${i} 缺少 lock_lp_token_amount Order data format error: Order ${i} missing lock_lp_token_amount`);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
result.lock_lp_sol_amount_sum += BigInt(order.lock_lp_sol_amount);
|
|
619
|
+
result.lock_lp_token_amount_sum += BigInt(order.lock_lp_token_amount);
|
|
620
|
+
} catch (error) {
|
|
621
|
+
if (error.message.includes('订单数据格式错误')) {
|
|
622
|
+
throw error;
|
|
623
|
+
}
|
|
624
|
+
throw new Error(`流动性计算错误:无法累加订单 ${i} 的锁定流动性 Liquidity calculation error: Cannot accumulate locked liquidity for order ${i} - ${error.message}`);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
counti += 1;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// 如果遍历的订单数小于等于onceMaxOrder,说明链表结束,需要计算无限流动性
|
|
633
|
+
if (orders.length <= onceMaxOrder && orders.length > 0) {
|
|
634
|
+
|
|
635
|
+
const lastOrder = orders[orders.length - 1];
|
|
636
|
+
if (!lastOrder || !lastOrder.lock_lp_end_price) {
|
|
637
|
+
throw new Error(`订单数据格式错误:最后一个订单缺少 lock_lp_end_price Order data format error: Last order missing lock_lp_end_price`);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
let lastEndPrice, minPrice;
|
|
641
|
+
try {
|
|
642
|
+
lastEndPrice = BigInt(lastOrder.lock_lp_end_price);
|
|
643
|
+
minPrice = CurveAMM.MIN_U128_PRICE;
|
|
644
|
+
} catch (error) {
|
|
645
|
+
throw new Error(`价格转换错误:无法转换最后订单价格或最小价格 Price conversion error: Cannot convert last order price or min price - ${error.message}`);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
if (lastEndPrice > minPrice) {
|
|
650
|
+
|
|
651
|
+
try {
|
|
652
|
+
const infiniteLiquidity = CurveAMM.sellFromPriceToPrice(lastEndPrice, minPrice);
|
|
653
|
+
if (infiniteLiquidity && Array.isArray(infiniteLiquidity) && infiniteLiquidity.length === 2) {
|
|
654
|
+
const [tokenAmount, solAmount] = infiniteLiquidity;
|
|
655
|
+
|
|
656
|
+
let prevFreeSolSum;
|
|
657
|
+
try {
|
|
658
|
+
prevFreeSolSum = result.free_lp_sol_amount_sum;
|
|
659
|
+
result.free_lp_sol_amount_sum += BigInt(solAmount);
|
|
660
|
+
result.free_lp_token_amount_sum += BigInt(tokenAmount);
|
|
661
|
+
result.has_infinite_lp = true;
|
|
662
|
+
} catch (error) {
|
|
663
|
+
throw new Error(`流动性计算错误:无法转换无限流动性数值 Liquidity calculation error: Cannot convert infinite liquidity values - ${error.message}`);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// 进入无限流动性后,计算实际获得的SOL数量
|
|
667
|
+
if (result.real_lp_sol_amount === 0n) {
|
|
668
|
+
if (result.free_lp_token_amount_sum >= sellTokenAmountBigInt) {
|
|
669
|
+
// 无限流动性够卖出需求了
|
|
670
|
+
try {
|
|
671
|
+
const actualSellAmount = sellTokenAmountBigInt - (result.free_lp_token_amount_sum - BigInt(tokenAmount));
|
|
672
|
+
const [, preciseSol] = CurveAMM.sellFromPriceWithTokenInput(lastEndPrice, actualSellAmount);
|
|
673
|
+
result.real_lp_sol_amount = prevFreeSolSum + preciseSol;
|
|
674
|
+
result.force_close_num = counti; // 强平订单数量
|
|
675
|
+
} catch (error) {
|
|
676
|
+
throw new Error(`流动性计算错误:无限流动性精确SOL计算失败 Liquidity calculation error: Infinite liquidity precise SOL calculation failed - ${error.message}`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
} else {
|
|
682
|
+
throw new Error(`无限流动性计算失败a:返回数据格式错误 Infinite liquidity calculation failure: Invalid return data format`);
|
|
683
|
+
}
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (error.message.includes('无限流动性计算失败') || error.message.includes('流动性计算错误') || error.message.includes('订单数据格式错误') || error.message.includes('价格转换错误')) {
|
|
686
|
+
throw error;
|
|
687
|
+
}
|
|
688
|
+
throw new Error(`无限流动性计算失败b:${error.message} Infinite liquidity calculation failure: ${error.message}`);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return result;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
module.exports = {
|
|
697
|
+
calcLiqTokenBuy,
|
|
698
|
+
calcLiqTokenSell
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
|