pinpet-sdk 2.1.13 → 2.1.15

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "address": "AGpTikur4Sxf9xutmJrwVmyKWYQEsqzoiiEm2mvr82cp",
2
+ "address": "F2FzigE1Z374iDvreiM6hZQe6oGXgomJfv8PyybvUXye",
3
3
  "metadata": {
4
4
  "name": "pinpet",
5
5
  "version": "0.1.0",
@@ -2481,7 +2481,7 @@
2481
2481
  {
2482
2482
  "code": 6003,
2483
2483
  "name": "SellCalculationOverflow",
2484
- "msg": "Sell trade calculation overflow"
2484
+ "msg": "Sell trade calculation overflow"
2485
2485
  },
2486
2486
  {
2487
2487
  "code": 6004,
@@ -29,7 +29,7 @@ const { calcLiqTokenBuy, calcLiqTokenSell } = require('./calcLiq');
29
29
  async function simulateTokenBuy(mint, buyTokenAmount, passOrder = null, lastPrice = null, ordersData = null) {
30
30
  // 获取价格和订单数据
31
31
 
32
- //console.log('simulateTokenBuy', mint, buyTokenAmount, passOrder, lastPrice, ordersData);
32
+ console.log('simulateTokenBuy', mint, buyTokenAmount, passOrder, lastPrice, ordersData);
33
33
 
34
34
  let price = lastPrice;
35
35
  if (!price) {
@@ -74,17 +74,20 @@ async function simulateTokenBuy(mint, buyTokenAmount, passOrder = null, lastPric
74
74
  curveData.initialVirtualToken
75
75
  );
76
76
 
77
- // console.log('\n=== calcLiqTokenBuy 返回结果 ===');
78
- // console.log('自由流动性 SOL 总量:', liqResult.free_lp_sol_amount_sum.toString());
79
- // console.log('自由流动性 Token 总量:', liqResult.free_lp_token_amount_sum.toString());
80
- // console.log('锁定流动性 SOL 总量:', liqResult.lock_lp_sol_amount_sum.toString());
81
- // console.log('锁定流动性 Token 总量:', liqResult.lock_lp_token_amount_sum.toString());
82
- // console.log('是否包含无限流动性:', liqResult.has_infinite_lp);
83
- // console.log('跳过的订单索引:', liqResult.pass_order_id);
84
- // console.log('需要强平的订单数量:', liqResult.force_close_num);
85
- // console.log('理想 SOL 使用量:', liqResult.ideal_lp_sol_amount.toString());
86
- // console.log('实际 SOL 使用量:', liqResult.real_lp_sol_amount.toString());
87
- // console.log('===============================\n');
77
+ console.log("liqResult:",liqResult);
78
+
79
+
80
+ console.log('\n=== calcLiqTokenBuy 返回结果 ===');
81
+ console.log('自由流动性 SOL 总量:', liqResult.free_lp_sol_amount_sum.toString());
82
+ console.log('自由流动性 Token 总量:', liqResult.free_lp_token_amount_sum.toString());
83
+ console.log('锁定流动性 SOL 总量:', liqResult.lock_lp_sol_amount_sum.toString());
84
+ console.log('锁定流动性 Token 总量:', liqResult.lock_lp_token_amount_sum.toString());
85
+ console.log('是否包含无限流动性:', liqResult.has_infinite_lp);
86
+ console.log('跳过的订单索引:', liqResult.pass_order_id);
87
+ console.log('需要强平的订单数量:', liqResult.force_close_num);
88
+ console.log('理想 SOL 使用量:', liqResult.ideal_lp_sol_amount.toString());
89
+ console.log('实际 SOL 使用量:', liqResult.real_lp_sol_amount.toString());
90
+ console.log('===============================\n');
88
91
 
89
92
  // Convert to BigInt for calculations
90
93
  const buyTokenAmountBig = BigInt(buyTokenAmount);
@@ -0,0 +1,257 @@
1
+
2
+ const CurveAMM = require('../../utils/curve_amm');
3
+
4
+ /**
5
+ * 计算使用指定SOL数量买入时能获得的Token数量
6
+ * @param {bigint|string} price - 当前交易价格 (u128格式)
7
+ * @param {bigint|string|number} buySolAmount - 需要花费的SOL数量 (lamports, 9位精度)
8
+ * @param {Array} orders - 锁定流动性的订单数组
9
+ * @param {number} onceMaxOrder - 单次循环最大订单数
10
+ * @param {string|number|null} passOrderID - 需要跳过的订单ID(与order_id字段比较)
11
+ * @param {string|number|Decimal|null} initialVirtualSol - 流动池SOL数量
12
+ * @param {string|number|Decimal|null} initialVirtualToken - 流动池Token数量
13
+ * @returns {Object} { tokenAmount: bigint, msg: string, closedOrdersCount: number }
14
+ */
15
+ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID = null, initialVirtualSol = null, initialVirtualToken = null){
16
+
17
+ // 1. 参数验证
18
+ // 转换为 bigint 以便比较
19
+ let priceBigInt;
20
+ let buySolAmountBigInt;
21
+
22
+ try {
23
+ priceBigInt = typeof price === 'bigint' ? price : BigInt(price);
24
+ buySolAmountBigInt = typeof buySolAmount === 'bigint' ? buySolAmount : BigInt(buySolAmount);
25
+ } catch (error) {
26
+ return {
27
+ tokenAmount: 0n,
28
+ msg: '参数格式错误:无法转换为bigint',
29
+ closedOrdersCount: 0
30
+ };
31
+ }
32
+
33
+ // 检查价格和金额是否有效
34
+ if (priceBigInt <= 0n) {
35
+ return {
36
+ tokenAmount: 0n,
37
+ msg: '计算失败:价格必须大于0',
38
+ closedOrdersCount: 0
39
+ };
40
+ }
41
+
42
+ if (buySolAmountBigInt <= 0n) {
43
+ return {
44
+ tokenAmount: 0n,
45
+ msg: '计算失败:买入金额必须大于0',
46
+ closedOrdersCount: 0
47
+ };
48
+ }
49
+
50
+ // 2. 设置默认流动池参数
51
+ const virtualSol = initialVirtualSol !== null ? initialVirtualSol : CurveAMM.INITIAL_SOL_RESERVE_DECIMAL;
52
+ const virtualToken = initialVirtualToken !== null ? initialVirtualToken : CurveAMM.INITIAL_TOKEN_RESERVE_DECIMAL;
53
+
54
+ // 3. 处理空订单情况(第一阶段)
55
+ if (!orders || orders.length === 0) {
56
+ // 直接计算完整流动性下的买入
57
+ const result = CurveAMM.buyFromPriceWithSolInputWithParams(
58
+ price,
59
+ buySolAmount,
60
+ virtualSol,
61
+ virtualToken
62
+ );
63
+
64
+ if (result === null) {
65
+ return {
66
+ tokenAmount: 0n,
67
+ msg: '计算失败:价格或参数无效',
68
+ closedOrdersCount: 0
69
+ };
70
+ }
71
+
72
+ const [endPrice, tokenAmount] = result;
73
+ return {
74
+ tokenAmount: tokenAmount,
75
+ msg: '流动性完整,无锁定订单',
76
+ closedOrdersCount: 0
77
+ };
78
+ }
79
+
80
+ // 4. 处理有订单的情况(第二阶段:分段流动性计算)
81
+
82
+ // 初始化变量
83
+ let currentPrice = priceBigInt; // 当前价格指针
84
+ let remainingSol = buySolAmountBigInt; // 剩余可用 SOL
85
+ let totalTokenAmount = 0n; // 累计获得的 token
86
+ let closedOrdersCount = 0; // 平仓订单数量
87
+ let processedOrders = 0; // 已处理订单数
88
+
89
+ // 检查当前价格是否高于第一个订单的结束价格
90
+ if (orders.length > 0) {
91
+ const firstOrderEndPrice = typeof orders[0].lock_lp_end_price === 'bigint'
92
+ ? orders[0].lock_lp_end_price
93
+ : BigInt(orders[0].lock_lp_end_price);
94
+
95
+ if (currentPrice >= firstOrderEndPrice) {
96
+ return {
97
+ tokenAmount: 0n,
98
+ msg: '错误:当前价格已高于第一个订单的结束价格',
99
+ closedOrdersCount: 0
100
+ };
101
+ }
102
+ }
103
+
104
+ // 遍历订单(最多 onceMaxOrder 个)
105
+ for (let i = 0; i < orders.length && processedOrders < onceMaxOrder; i++) {
106
+ const order = orders[i];
107
+
108
+ // 检查是否需要跳过此订单
109
+ if (passOrderID !== null && order.order_id !== undefined) {
110
+ // 将两者都转换为字符串进行比较
111
+ const orderIdStr = String(order.order_id);
112
+ const passOrderIdStr = String(passOrderID);
113
+
114
+ if (orderIdStr === passOrderIdStr) {
115
+ // 跳过此订单,不处理其锁定区间,继续下一个订单
116
+ continue;
117
+ }
118
+ }
119
+
120
+ // 转换订单价格为 bigint
121
+ let lockStartPrice, lockEndPrice;
122
+ try {
123
+ lockStartPrice = typeof order.lock_lp_start_price === 'bigint'
124
+ ? order.lock_lp_start_price
125
+ : BigInt(order.lock_lp_start_price);
126
+ lockEndPrice = typeof order.lock_lp_end_price === 'bigint'
127
+ ? order.lock_lp_end_price
128
+ : BigInt(order.lock_lp_end_price);
129
+ } catch (error) {
130
+ return {
131
+ tokenAmount: 0n,
132
+ msg: `错误:订单${i}的价格格式无效`,
133
+ closedOrdersCount: closedOrdersCount
134
+ };
135
+ }
136
+
137
+ // 步骤1:计算可用区间(currentPrice → lockStartPrice)
138
+ if (currentPrice < lockStartPrice) {
139
+ // 1.1 计算这段区间需要多少 SOL 和能获得多少 token
140
+ const result = CurveAMM.buyFromPriceToPriceWithParams(
141
+ currentPrice,
142
+ lockStartPrice,
143
+ virtualSol,
144
+ virtualToken
145
+ );
146
+
147
+ // 检查计算是否成功
148
+ if (result === null) {
149
+ return {
150
+ tokenAmount: 0n,
151
+ msg: `错误:计算价格区间失败(订单${i})`,
152
+ closedOrdersCount: closedOrdersCount
153
+ };
154
+ }
155
+
156
+ const [solNeeded, tokenGained] = result;
157
+
158
+ // 1.2 判断剩余 SOL 是否足够
159
+ if (remainingSol >= solNeeded) {
160
+ // 足够:买完这段区间,继续下一段
161
+ remainingSol -= solNeeded;
162
+ totalTokenAmount += tokenGained;
163
+ currentPrice = lockStartPrice;
164
+ } else {
165
+ // 不够:用完剩余 SOL,计算能买多少,然后返回
166
+ const finalResult = CurveAMM.buyFromPriceWithSolInputWithParams(
167
+ currentPrice,
168
+ remainingSol,
169
+ virtualSol,
170
+ virtualToken
171
+ );
172
+
173
+ if (finalResult === null) {
174
+ return {
175
+ tokenAmount: 0n,
176
+ msg: '错误:计算最终买入失败',
177
+ closedOrdersCount: closedOrdersCount
178
+ };
179
+ }
180
+
181
+ const [finalPrice, finalTokenGained] = finalResult;
182
+ totalTokenAmount += finalTokenGained;
183
+
184
+ return {
185
+ tokenAmount: totalTokenAmount,
186
+ msg: `SOL用完,最终价格: ${finalPrice.toString()}`,
187
+ closedOrdersCount: closedOrdersCount
188
+ };
189
+ }
190
+ }
191
+
192
+ // 步骤2:跳过锁定区间(lockStartPrice → lockEndPrice)
193
+ currentPrice = lockEndPrice;
194
+ processedOrders++;
195
+
196
+ // 步骤3:判断是否平仓
197
+ // 如果价格到达 lockEndPrice,说明这个订单被平仓
198
+ closedOrdersCount++;
199
+
200
+ // 检查 SOL 是否已用完
201
+ if (remainingSol === 0n) {
202
+ return {
203
+ tokenAmount: totalTokenAmount,
204
+ msg: `SOL刚好用完,最终价格: ${currentPrice.toString()}`,
205
+ closedOrdersCount: closedOrdersCount
206
+ };
207
+ }
208
+ }
209
+
210
+ // 步骤4:处理最后的无限流动性区间
211
+ // 所有订单处理完后,用剩余 SOL 继续买入
212
+ if (remainingSol > 0n) {
213
+ const finalResult = CurveAMM.buyFromPriceWithSolInputWithParams(
214
+ currentPrice,
215
+ remainingSol,
216
+ virtualSol,
217
+ virtualToken
218
+ );
219
+
220
+ if (finalResult === null) {
221
+ return {
222
+ tokenAmount: 0n,
223
+ msg: '错误:计算无限流动性区间失败',
224
+ closedOrdersCount: closedOrdersCount
225
+ };
226
+ }
227
+
228
+ const [finalPrice, finalTokenGained] = finalResult;
229
+ totalTokenAmount += finalTokenGained;
230
+
231
+ return {
232
+ tokenAmount: totalTokenAmount,
233
+ msg: `买入完成,最终价格: ${finalPrice.toString()}`,
234
+ closedOrdersCount: closedOrdersCount
235
+ };
236
+ }
237
+
238
+ // 步骤5:SOL 刚好用完
239
+ return {
240
+ tokenAmount: totalTokenAmount,
241
+ msg: `SOL刚好用完,最终价格: ${currentPrice.toString()}`,
242
+ closedOrdersCount: closedOrdersCount
243
+ };
244
+
245
+ }
246
+
247
+
248
+ function calcLiqSolSell(price, sellSolAmount, orders, onceMaxOrder, passOrder = null, initialVirtualSol = null, initialVirtualToken = null) {
249
+
250
+
251
+ }
252
+
253
+
254
+ module.exports = {
255
+ calcLiqSolBuy,
256
+ calcLiqSolSell
257
+ };
@@ -2,7 +2,7 @@ const CurveAMM = require('../utils/curve_amm');
2
2
  const { simulateLongStopLoss, simulateShortStopLoss, simulateLongSolStopLoss, simulateShortSolStopLoss } = require('./simulator/long_shrot_stop');
3
3
  const { simulateTokenBuy, simulateTokenSell } = require('./simulator/buy_sell_token');
4
4
  const { simulateLongClose, simulateShortClose } = require('./simulator/close_indices');
5
-
5
+ const {calcLiqSolBuy,calcLiqSolSell } = require('./simulator/calc_sol_liq');
6
6
 
7
7
 
8
8
 
@@ -208,6 +208,12 @@ class SimulatorModule {
208
208
  const priceResult = await this.sdk.data.price(mint);
209
209
  const ordersResult = await this.sdk.data.orders(mint, { type: 'down_orders' });
210
210
 
211
+ console.log("ordersResult:",ordersResult)
212
+
213
+ const upOrdersResult = await this.sdk.data.orders(mint, { type: 'up_orders' });
214
+ console.log("upOrdersResult:",upOrdersResult);
215
+ console.log("upOrdersResult:",upOrdersResult.data.orders);
216
+
211
217
  if (!priceResult || !ordersResult) {
212
218
  return {
213
219
  success: false,
@@ -227,6 +233,15 @@ class SimulatorModule {
227
233
  const solInDecimal = Number(solAmountBigInt) / 1e9; // Convert lamports to SOL
228
234
  const estimatedTokenAmount = BigInt(Math.floor((solInDecimal / priceDecimal) * 1e9)); // Convert to token lamports (9-digit precision)
229
235
 
236
+ // Get curve account data for initialVirtualSol and initialVirtualToken
237
+ const curveAccount = await this.sdk.chain.getCurveAccount(mint);
238
+ const initialVirtualSol = curveAccount.initialVirtualSol;
239
+ const initialVirtualToken = curveAccount.initialVirtualToken;
240
+
241
+ const reSolBuy = calcLiqSolBuy(currentPrice, buySolAmount, upOrdersResult.data.orders, 50, null, initialVirtualSol, initialVirtualToken);
242
+
243
+
244
+
230
245
  // Call simulateTokenBuy with estimated amount
231
246
  const tokenBuyResult = await this.simulateTokenBuy(mint, estimatedTokenAmount, null, priceResult, ordersResult);
232
247
 
package/src/sdk.js CHANGED
@@ -62,7 +62,7 @@ class PinPetSdk {
62
62
  this.pinPetFastApiUrl = this.options.pinPetFastApiUrl;
63
63
 
64
64
  // Maximum number of orders that can be processed at once in the contract
65
- this.MAX_ORDERS_COUNT = 9
65
+ this.MAX_ORDERS_COUNT = 50
66
66
  // Maximum number of orders to fetch during queries
67
67
  this.FIND_MAX_ORDERS_COUNT = 1000
68
68
 
@@ -25,13 +25,13 @@ const DEFAULT_NETWORKS = {
25
25
  LOCALNET: {
26
26
  name: 'localnet',
27
27
  defaultDataSource: 'fast', // 'fast' or 'chain'
28
- // solanaEndpoint: 'http://127.0.0.1:8899',
29
- // pinPetFastApiUrl: 'http://127.0.0.1:3000',
30
- solanaEndpoint: 'http://162.250.124.66:8899',
31
- pinPetFastApiUrl: 'http://162.250.124.66:3000',
28
+ solanaEndpoint: 'http://127.0.0.1:8899',
29
+ pinPetFastApiUrl: 'http://127.0.0.1:3000',
30
+ // solanaEndpoint: 'http://162.250.124.66:8899',
31
+ // pinPetFastApiUrl: 'http://162.250.124.66:3000',
32
32
  feeRecipient: 'GesAj2dTn2wdNcxj4x8qsqS9aNRVPBPkE76aaqg7skxu',
33
33
  baseFeeRecipient: '5YHi1HsxobLiTD6NQfHJQpoPoRjMuNyXp4RroTvR6dKi',
34
- paramsAccount: 'BvChe3C88ezFvcSutX5TsTUnUdToHAHqwfSQ85cmNq1A'
34
+ paramsAccount: '8tn4XdqWAAh97WwfLrDrwnagRsQp7Nu5nrUmXVBJvgMU'
35
35
  }
36
36
  };
37
37