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,300 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
const { calcLiqTokenBuy, calcLiqTokenSell } = require('./calcLiq');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Simulate token buy transaction - calculate if target token amount can be purchased
|
|
7
|
+
* 模拟以 Token 数量为目标的买入交易 - 计算是否能买到指定数量的 Token
|
|
8
|
+
* @param {string} mint - Token address 代币地址
|
|
9
|
+
* @param {bigint|string|number} buyTokenAmount - Target token amount to buy 目标购买的 Token 数量
|
|
10
|
+
* @param {string} passOrder - Optional order address to skip (won't be liquidated) 可选的跳过订单地址
|
|
11
|
+
* @param {Object|null} lastPrice - Token price info, default null
|
|
12
|
+
* @param {Object|null} ordersData - Orders response object, default null
|
|
13
|
+
* @returns {Promise<Object>} Token buy simulation result with the following structure:
|
|
14
|
+
* - liqResult: {Object} Complete liquidity calculation result from calcLiqTokenBuy, containing:
|
|
15
|
+
* - free_lp_sol_amount_sum: {bigint} Total available free liquidity SOL amount
|
|
16
|
+
* - free_lp_token_amount_sum: {bigint} Total available free liquidity token amount
|
|
17
|
+
* - lock_lp_sol_amount_sum: {bigint} Total locked liquidity SOL amount
|
|
18
|
+
* - lock_lp_token_amount_sum: {bigint} Total locked liquidity token amount
|
|
19
|
+
* - has_infinite_lp: {boolean} Whether includes infinite liquidity beyond last order
|
|
20
|
+
* - pass_order_id: {number} Index of skipped order in array (-1 if none skipped)
|
|
21
|
+
* - force_close_num: {number} Number of orders that need force closure for target amount
|
|
22
|
+
* - ideal_lp_sol_amount: {bigint} Theoretical minimum SOL required at current price
|
|
23
|
+
* - real_lp_sol_amount: {bigint} Actual SOL required considering real liquidity distribution
|
|
24
|
+
* - completion: {string} Purchase completion percentage as decimal string (e.g., "85.2", "100.0")
|
|
25
|
+
* - slippage: {string} Price slippage percentage as decimal string (e.g., "2.5", "0.8")
|
|
26
|
+
* - suggestedTokenAmount: {string} Recommended token amount to buy based on available liquidity
|
|
27
|
+
* - suggestedSolAmount: {string} Required SOL amount for suggested token purchase
|
|
28
|
+
*/
|
|
29
|
+
async function simulateTokenBuy(mint, buyTokenAmount, passOrder = null, lastPrice = null, ordersData = null) {
|
|
30
|
+
// 获取价格和订单数据
|
|
31
|
+
|
|
32
|
+
//console.log('simulateTokenBuy', mint, buyTokenAmount, passOrder, lastPrice, ordersData);
|
|
33
|
+
|
|
34
|
+
let price = lastPrice;
|
|
35
|
+
if (!price) {
|
|
36
|
+
price = await this.sdk.data.price(mint);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let orders;
|
|
40
|
+
if (!ordersData) {
|
|
41
|
+
const ordersResponse = await this.sdk.data.orders(mint, {
|
|
42
|
+
type: 'up_orders',
|
|
43
|
+
limit: this.sdk.MAX_ORDERS_COUNT + 1
|
|
44
|
+
});
|
|
45
|
+
// 提取实际的订单数组
|
|
46
|
+
orders = ordersResponse.data.orders;
|
|
47
|
+
} else {
|
|
48
|
+
// 如果传入了 ordersData,从响应对象中提取订单数组并限制长度
|
|
49
|
+
orders = ordersData.data.orders.slice(0, this.sdk.MAX_ORDERS_COUNT + 1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// console.log('simulateTokenBuy 获取的数据:');
|
|
53
|
+
// console.log('价格:', price);
|
|
54
|
+
// console.log('订单数量:', orders.length);
|
|
55
|
+
// orders.forEach((order, i) => console.log(`订单${i}: start=${order.lock_lp_start_price}, end=${order.lock_lp_end_price}, sol=${order.lock_lp_sol_amount}, token=${order.lock_lp_token_amount}`));
|
|
56
|
+
|
|
57
|
+
// 调用 calcLiqTokenBuy 进行流动性计算
|
|
58
|
+
try {
|
|
59
|
+
const liqResult = calcLiqTokenBuy(
|
|
60
|
+
price,
|
|
61
|
+
buyTokenAmount,
|
|
62
|
+
orders,
|
|
63
|
+
this.sdk.MAX_ORDERS_COUNT,
|
|
64
|
+
passOrder
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// console.log('\n=== calcLiqTokenBuy 返回结果 ===');
|
|
68
|
+
// console.log('自由流动性 SOL 总量:', liqResult.free_lp_sol_amount_sum.toString());
|
|
69
|
+
// console.log('自由流动性 Token 总量:', liqResult.free_lp_token_amount_sum.toString());
|
|
70
|
+
// console.log('锁定流动性 SOL 总量:', liqResult.lock_lp_sol_amount_sum.toString());
|
|
71
|
+
// console.log('锁定流动性 Token 总量:', liqResult.lock_lp_token_amount_sum.toString());
|
|
72
|
+
// console.log('是否包含无限流动性:', liqResult.has_infinite_lp);
|
|
73
|
+
// console.log('跳过的订单索引:', liqResult.pass_order_id);
|
|
74
|
+
// console.log('需要强平的订单数量:', liqResult.force_close_num);
|
|
75
|
+
// console.log('理想 SOL 使用量:', liqResult.ideal_lp_sol_amount.toString());
|
|
76
|
+
// console.log('实际 SOL 使用量:', liqResult.real_lp_sol_amount.toString());
|
|
77
|
+
// console.log('===============================\n');
|
|
78
|
+
|
|
79
|
+
// Convert to BigInt for calculations
|
|
80
|
+
const buyTokenAmountBig = BigInt(buyTokenAmount);
|
|
81
|
+
const freeTokenAmount = BigInt(liqResult.free_lp_token_amount_sum);
|
|
82
|
+
const realSolAmount = BigInt(liqResult.real_lp_sol_amount);
|
|
83
|
+
const idealSolAmount = BigInt(liqResult.ideal_lp_sol_amount);
|
|
84
|
+
|
|
85
|
+
// 1. Calculate completion percentage
|
|
86
|
+
let completionPercentage;
|
|
87
|
+
if (freeTokenAmount >= buyTokenAmountBig) {
|
|
88
|
+
completionPercentage = "100.0";
|
|
89
|
+
} else {
|
|
90
|
+
const percentage = Math.floor((Number(freeTokenAmount) / Number(buyTokenAmountBig)) * 1000) / 10;
|
|
91
|
+
completionPercentage = percentage.toFixed(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 2. Calculate slippage percentage and get final SOL amount
|
|
95
|
+
let slippagePercentage;
|
|
96
|
+
let suggestedLiquidity;
|
|
97
|
+
let finalRealSolAmount = realSolAmount;
|
|
98
|
+
|
|
99
|
+
if (realSolAmount > 0n) {
|
|
100
|
+
// Normal case: calculate slippage
|
|
101
|
+
const diff = idealSolAmount > realSolAmount ? idealSolAmount - realSolAmount : realSolAmount - idealSolAmount;
|
|
102
|
+
const slippage = Math.floor((Number(diff) / Number(idealSolAmount)) * 1000) / 10;
|
|
103
|
+
slippagePercentage = slippage.toFixed(1);
|
|
104
|
+
} else {
|
|
105
|
+
// Special case: real SOL amount is 0, need to recalculate with suggested liquidity
|
|
106
|
+
const suggestedAmount = (freeTokenAmount * BigInt(this.sdk.SUGGEST_LIQ_RATIO)) / 1000n;
|
|
107
|
+
|
|
108
|
+
const recalcResult = calcLiqTokenBuy(
|
|
109
|
+
price,
|
|
110
|
+
suggestedAmount,
|
|
111
|
+
orders,
|
|
112
|
+
this.sdk.MAX_ORDERS_COUNT,
|
|
113
|
+
passOrder
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const recalcRealSol = BigInt(recalcResult.real_lp_sol_amount);
|
|
117
|
+
const recalcIdealSol = BigInt(recalcResult.ideal_lp_sol_amount);
|
|
118
|
+
|
|
119
|
+
if (recalcRealSol <= 0n) {
|
|
120
|
+
throw new Error('Recalculated real SOL amount should be greater than 0');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
finalRealSolAmount = recalcRealSol;
|
|
124
|
+
|
|
125
|
+
const diff = recalcIdealSol > recalcRealSol ? recalcIdealSol - recalcRealSol : recalcRealSol - recalcIdealSol;
|
|
126
|
+
const slippage = Math.floor((Number(diff) / Number(recalcIdealSol)) * 1000) / 10;
|
|
127
|
+
slippagePercentage = slippage.toFixed(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 3. Calculate suggested liquidity
|
|
131
|
+
if (completionPercentage === "100.0") {
|
|
132
|
+
suggestedLiquidity = buyTokenAmountBig.toString();
|
|
133
|
+
} else {
|
|
134
|
+
const suggested = (freeTokenAmount * BigInt(this.sdk.SUGGEST_LIQ_RATIO)) / 1000n;
|
|
135
|
+
suggestedLiquidity = suggested.toString();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
liqResult,
|
|
140
|
+
completion: completionPercentage,
|
|
141
|
+
slippage: slippagePercentage,
|
|
142
|
+
suggestedTokenAmount: suggestedLiquidity,
|
|
143
|
+
suggestedSolAmount: finalRealSolAmount.toString()
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error('calcLiqTokenBuy 调用失败:', error);
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Simulate token sell transaction analysis
|
|
154
|
+
* @param {string} mint - Token address
|
|
155
|
+
* @param {bigint|string|number} sellTokenAmount - Token amount to sell (u64 format, precision 10^6)
|
|
156
|
+
* @param {string} passOrder - Optional order address to skip (won't be liquidated) 可选的跳过订单地址
|
|
157
|
+
* @param {Object|null} lastPrice - Token price info, default null
|
|
158
|
+
* @param {Object|null} ordersData - Orders response object, default null
|
|
159
|
+
* @returns {Promise<Object>} Token sell simulation result with the following structure:
|
|
160
|
+
* - liqResult: {Object} Complete liquidity calculation result from calcLiqTokenSell, containing:
|
|
161
|
+
* - free_lp_sol_amount_sum: {bigint} Total available free liquidity SOL obtainable from selling
|
|
162
|
+
* - free_lp_token_amount_sum: {bigint} Maximum tokens sellable without force closing orders
|
|
163
|
+
* - lock_lp_sol_amount_sum: {bigint} Total locked liquidity SOL amount (excluding skipped orders)
|
|
164
|
+
* - lock_lp_token_amount_sum: {bigint} Total locked liquidity token amount (excluding skipped orders)
|
|
165
|
+
* - has_infinite_lp: {boolean} Whether includes infinite liquidity to minimum price
|
|
166
|
+
* - pass_order_id: {number} Index of skipped order in array (-1 if none skipped)
|
|
167
|
+
* - force_close_num: {number} Number of orders that need force closure for target sell amount
|
|
168
|
+
* - ideal_lp_sol_amount: {bigint} Theoretical maximum SOL obtainable at current price
|
|
169
|
+
* - real_lp_sol_amount: {bigint} Actual SOL obtainable considering real liquidity distribution
|
|
170
|
+
* - completion: {string} Sell completion percentage as decimal string (e.g., "85.2", "100.0")
|
|
171
|
+
* - slippage: {string} Price slippage percentage as decimal string (e.g., "2.5", "0.8")
|
|
172
|
+
* - suggestedTokenAmount: {string} Recommended token amount to sell based on available liquidity
|
|
173
|
+
* - suggestedSolAmount: {string} Expected SOL amount from suggested token sale
|
|
174
|
+
*/
|
|
175
|
+
async function simulateTokenSell(mint, sellTokenAmount, passOrder = null, lastPrice = null, ordersData = null) {
|
|
176
|
+
// 获取价格和订单数据
|
|
177
|
+
let price = lastPrice;
|
|
178
|
+
if (!price) {
|
|
179
|
+
price = await this.sdk.data.price(mint);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let orders;
|
|
183
|
+
if (!ordersData) {
|
|
184
|
+
const ordersResponse = await this.sdk.data.orders(mint, {
|
|
185
|
+
type: 'down_orders',
|
|
186
|
+
limit: this.sdk.MAX_ORDERS_COUNT + 1
|
|
187
|
+
});
|
|
188
|
+
// 提取实际的订单数组
|
|
189
|
+
orders = ordersResponse.data.orders;
|
|
190
|
+
} else {
|
|
191
|
+
// 如果传入了 ordersData,从响应对象中提取订单数组并限制长度
|
|
192
|
+
orders = ordersData.data.orders.slice(0, this.sdk.MAX_ORDERS_COUNT + 1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// console.log('simulateTokenSell 获取的数据:');
|
|
196
|
+
// console.log('价格:', price);
|
|
197
|
+
// console.log('订单数量:', orders.length);
|
|
198
|
+
// orders.forEach((order, i) => console.log(`订单${i}: start=${order.lock_lp_start_price}, end=${order.lock_lp_end_price}, sol=${order.lock_lp_sol_amount}, token=${order.lock_lp_token_amount}`));
|
|
199
|
+
|
|
200
|
+
// 调用 calcLiqTokenSell 进行流动性计算
|
|
201
|
+
try {
|
|
202
|
+
const liqResult = calcLiqTokenSell(
|
|
203
|
+
price,
|
|
204
|
+
sellTokenAmount,
|
|
205
|
+
orders,
|
|
206
|
+
this.sdk.MAX_ORDERS_COUNT,
|
|
207
|
+
passOrder
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// console.log('\n=== calcLiqTokenSell 返回结果 ===');
|
|
211
|
+
// console.log('自由流动性 SOL 总量:', liqResult.free_lp_sol_amount_sum.toString());
|
|
212
|
+
// console.log('自由流动性 Token 总量:', liqResult.free_lp_token_amount_sum.toString());
|
|
213
|
+
// console.log('锁定流动性 SOL 总量:', liqResult.lock_lp_sol_amount_sum.toString());
|
|
214
|
+
// console.log('锁定流动性 Token 总量:', liqResult.lock_lp_token_amount_sum.toString());
|
|
215
|
+
// console.log('是否包含无限流动性:', liqResult.has_infinite_lp);
|
|
216
|
+
// console.log('跳过的订单索引:', liqResult.pass_order_id);
|
|
217
|
+
// console.log('需要强平的订单数量:', liqResult.force_close_num);
|
|
218
|
+
// console.log('理想 SOL 获得量:', liqResult.ideal_lp_sol_amount.toString());
|
|
219
|
+
// console.log('实际 SOL 获得量:', liqResult.real_lp_sol_amount.toString());
|
|
220
|
+
// console.log('===============================\n');
|
|
221
|
+
|
|
222
|
+
// Convert to BigInt for calculations
|
|
223
|
+
const sellTokenAmountBig = BigInt(sellTokenAmount);
|
|
224
|
+
const freeTokenAmount = BigInt(liqResult.free_lp_token_amount_sum);
|
|
225
|
+
const realSolAmount = BigInt(liqResult.real_lp_sol_amount);
|
|
226
|
+
const idealSolAmount = BigInt(liqResult.ideal_lp_sol_amount);
|
|
227
|
+
|
|
228
|
+
// 1. Calculate completion percentage
|
|
229
|
+
let completionPercentage;
|
|
230
|
+
if (freeTokenAmount >= sellTokenAmountBig) {
|
|
231
|
+
completionPercentage = "100.0";
|
|
232
|
+
} else {
|
|
233
|
+
const percentage = Math.floor((Number(freeTokenAmount) / Number(sellTokenAmountBig)) * 1000) / 10;
|
|
234
|
+
completionPercentage = percentage.toFixed(1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 2. Calculate slippage percentage and get final SOL amount
|
|
238
|
+
let slippagePercentage;
|
|
239
|
+
let suggestedLiquidity;
|
|
240
|
+
let finalRealSolAmount = realSolAmount;
|
|
241
|
+
|
|
242
|
+
if (realSolAmount > 0n) {
|
|
243
|
+
// Normal case: calculate slippage
|
|
244
|
+
const diff = idealSolAmount > realSolAmount ? idealSolAmount - realSolAmount : realSolAmount - idealSolAmount;
|
|
245
|
+
const slippage = Math.floor((Number(diff) / Number(idealSolAmount)) * 1000) / 10;
|
|
246
|
+
slippagePercentage = slippage.toFixed(1);
|
|
247
|
+
} else {
|
|
248
|
+
// Special case: real SOL amount is 0, need to recalculate with suggested liquidity
|
|
249
|
+
const suggestedAmount = (freeTokenAmount * BigInt(this.sdk.SUGGEST_LIQ_RATIO)) / 1000n;
|
|
250
|
+
|
|
251
|
+
const recalcResult = calcLiqTokenSell(
|
|
252
|
+
price,
|
|
253
|
+
suggestedAmount,
|
|
254
|
+
orders,
|
|
255
|
+
this.sdk.MAX_ORDERS_COUNT,
|
|
256
|
+
passOrder
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const recalcRealSol = BigInt(recalcResult.real_lp_sol_amount);
|
|
260
|
+
const recalcIdealSol = BigInt(recalcResult.ideal_lp_sol_amount);
|
|
261
|
+
|
|
262
|
+
if (recalcRealSol <= 0n) {
|
|
263
|
+
throw new Error('Recalculated real SOL amount should be greater than 0');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
finalRealSolAmount = recalcRealSol;
|
|
267
|
+
|
|
268
|
+
const diff = recalcIdealSol > recalcRealSol ? recalcIdealSol - recalcRealSol : recalcRealSol - recalcIdealSol;
|
|
269
|
+
const slippage = Math.floor((Number(diff) / Number(recalcIdealSol)) * 1000) / 10;
|
|
270
|
+
slippagePercentage = slippage.toFixed(1);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// 3. Calculate suggested liquidity
|
|
274
|
+
if (completionPercentage === "100.0") {
|
|
275
|
+
suggestedLiquidity = sellTokenAmountBig.toString();
|
|
276
|
+
} else {
|
|
277
|
+
const suggested = (freeTokenAmount * BigInt(this.sdk.SUGGEST_LIQ_RATIO)) / 1000n;
|
|
278
|
+
suggestedLiquidity = suggested.toString();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
liqResult,
|
|
283
|
+
completion: completionPercentage,
|
|
284
|
+
slippage: slippagePercentage,
|
|
285
|
+
suggestedTokenAmount: suggestedLiquidity,
|
|
286
|
+
suggestedSolAmount: finalRealSolAmount.toString()
|
|
287
|
+
};
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.error('calcLiqTokenSell 调用失败:', error.message);
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
module.exports = {
|
|
297
|
+
simulateTokenBuy,
|
|
298
|
+
simulateTokenSell
|
|
299
|
+
};
|
|
300
|
+
|