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.
- package/dist/pinpet-sdk.cjs.js +336 -61
- package/dist/pinpet-sdk.esm.js +336 -61
- package/dist/pinpet-sdk.js +336 -61
- package/dist/pinpet-sdk.js.map +1 -1
- package/package.json +1 -1
- package/src/idl/pinpet copy.json +3730 -0
- package/src/idl/pinpet.json +2 -2
- package/src/modules/simulator/buy_sell_token.js +15 -12
- package/src/modules/simulator/calc_sol_liq.js +257 -0
- package/src/modules/simulator.js +16 -1
- package/src/sdk.js +1 -1
- package/src/utils/constants.js +5 -5
package/src/idl/pinpet.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"address": "
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
+
};
|
package/src/modules/simulator.js
CHANGED
|
@@ -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 =
|
|
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
|
|
package/src/utils/constants.js
CHANGED
|
@@ -25,13 +25,13 @@ const DEFAULT_NETWORKS = {
|
|
|
25
25
|
LOCALNET: {
|
|
26
26
|
name: 'localnet',
|
|
27
27
|
defaultDataSource: 'fast', // 'fast' or 'chain'
|
|
28
|
-
|
|
29
|
-
|
|
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: '
|
|
34
|
+
paramsAccount: '8tn4XdqWAAh97WwfLrDrwnagRsQp7Nu5nrUmXVBJvgMU'
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
|