100x-sdk 1.0.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 +364 -0
- package/dist/100x-sdk.cjs.js +57601 -0
- package/dist/100x-sdk.cjs.js.map +1 -0
- package/dist/100x-sdk.esm.js +46234 -0
- package/dist/100x-sdk.esm.js.map +1 -0
- package/dist/100x-sdk.js +46245 -0
- package/dist/100x-sdk.js.map +1 -0
- package/dist/index.d.ts +386 -0
- package/package.json +69 -0
- package/src/idl/fun100x_localnet.json +3735 -0
- package/src/idl/fun100x_main.json +3735 -0
- package/src/index.js +50 -0
- package/src/modules/chain.js +1310 -0
- package/src/modules/fast.js +734 -0
- package/src/modules/param.js +171 -0
- package/src/modules/simulator/buy_sell_token.js +326 -0
- package/src/modules/simulator/calcLiq.js +778 -0
- package/src/modules/simulator/calc_sol_liq.js +268 -0
- package/src/modules/simulator/close_indices.js +217 -0
- package/src/modules/simulator/long_shrot_stop.js +1028 -0
- package/src/modules/simulator/stop_loss_utils.js +378 -0
- package/src/modules/simulator/utils.js +63 -0
- package/src/modules/simulator.js +386 -0
- package/src/modules/token.js +455 -0
- package/src/modules/tools.js +370 -0
- package/src/modules/trading.js +848 -0
- package/src/sdk.js +206 -0
- package/src/types/index.d.ts +386 -0
- package/src/utils/constants.js +57 -0
- package/src/utils/curve_amm.js +1215 -0
- package/src/utils/orderUtils.js +17 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
const CurveAMM = require('../utils/curve_amm');
|
|
2
|
+
const { simulateLongStopLoss, simulateShortStopLoss, simulateLongSolStopLoss, simulateShortSolStopLoss } = require('./simulator/long_shrot_stop');
|
|
3
|
+
const { simulateTokenBuy, simulateTokenSell } = require('./simulator/buy_sell_token');
|
|
4
|
+
const { simulateLongClose, simulateShortClose } = require('./simulator/close_indices');
|
|
5
|
+
const {calcLiqSolBuy,calcLiqSolSell } = require('./simulator/calc_sol_liq');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Simulator Module Class
|
|
11
|
+
*/
|
|
12
|
+
class SimulatorModule {
|
|
13
|
+
constructor(sdk) {
|
|
14
|
+
this.sdk = sdk;
|
|
15
|
+
|
|
16
|
+
// Liquidity reservation ratio - how much liquidity to reserve relative to the last locked liquidity
|
|
17
|
+
this.LIQUIDITY_RESERVATION = 100; // 100%;
|
|
18
|
+
// Price adjustment percentage
|
|
19
|
+
this.PRICE_ADJUSTMENT_PERCENTAGE = 0.5; // 0.5%
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Simulate token buy transaction - calculate if target token amount can be purchased
|
|
24
|
+
* 模拟以 Token 数量为目标的买入交易 - 计算是否能买到指定数量的 Token
|
|
25
|
+
* @param {string} mint - Token address 代币地址
|
|
26
|
+
* @param {bigint|string|number} buyTokenAmount - Target token amount to buy 目标购买的 Token 数量
|
|
27
|
+
* @param {string} passOrder - Optional order address to skip (won't be liquidated) 可选的跳过订单地址
|
|
28
|
+
* @param {Object|null} lastPrice - Token price info, default null
|
|
29
|
+
* @param {Object|null} ordersData - Orders response object, default null
|
|
30
|
+
* @returns {Promise<Object>} Token buy simulation result with the following structure:
|
|
31
|
+
* - liqResult: {Object} Complete liquidity calculation result from calcLiqTokenBuy, containing:
|
|
32
|
+
* - free_lp_sol_amount_sum: {bigint} Total available free liquidity SOL amount
|
|
33
|
+
* - free_lp_token_amount_sum: {bigint} Total available free liquidity token amount
|
|
34
|
+
* - lock_lp_sol_amount_sum: {bigint} Total locked liquidity SOL amount
|
|
35
|
+
* - lock_lp_token_amount_sum: {bigint} Total locked liquidity token amount
|
|
36
|
+
* - has_infinite_lp: {boolean} Whether includes infinite liquidity beyond last order
|
|
37
|
+
* - pass_order_id: {number} Index of skipped order in array (-1 if none skipped)
|
|
38
|
+
* - force_close_num: {number} Number of orders that need force closure for target amount
|
|
39
|
+
* - ideal_lp_sol_amount: {bigint} Theoretical minimum SOL required at current price
|
|
40
|
+
* - real_lp_sol_amount: {bigint} Actual SOL required considering real liquidity distribution
|
|
41
|
+
* - completion: {string} Purchase completion percentage as decimal string (e.g., "85.2", "100.0")
|
|
42
|
+
* - slippage: {string} Price slippage percentage as decimal string (e.g., "2.5", "0.8")
|
|
43
|
+
* - suggestedTokenAmount: {string} Recommended token amount to buy based on available liquidity
|
|
44
|
+
* - suggestedSolAmount: {string} Required SOL amount for suggested token purchase
|
|
45
|
+
*/
|
|
46
|
+
async simulateTokenBuy(mint, buyTokenAmount, passOrder = null, lastPrice = null, ordersData = null, curveData = null) {
|
|
47
|
+
return simulateTokenBuy.call(this, mint, buyTokenAmount, passOrder, lastPrice, ordersData, curveData);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Simulate token sell transaction analysis
|
|
52
|
+
* @param {string} mint - Token address
|
|
53
|
+
* @param {bigint|string|number} sellTokenAmount - Token amount to sell (u64 format, precision 10^9)
|
|
54
|
+
* @param {string} passOrder - Optional order address to skip (won't be liquidated) 可选的跳过订单地址
|
|
55
|
+
* @param {Object|null} lastPrice - Token price info, default null
|
|
56
|
+
* @param {Object|null} ordersData - Orders response object, default null
|
|
57
|
+
* @returns {Promise<Object>} Token sell simulation result with the following structure:
|
|
58
|
+
* - liqResult: {Object} Complete liquidity calculation result from calcLiqTokenSell, containing:
|
|
59
|
+
* - free_lp_sol_amount_sum: {bigint} Total available free liquidity SOL obtainable from selling
|
|
60
|
+
* - free_lp_token_amount_sum: {bigint} Maximum tokens sellable without force closing orders
|
|
61
|
+
* - lock_lp_sol_amount_sum: {bigint} Total locked liquidity SOL amount (excluding skipped orders)
|
|
62
|
+
* - lock_lp_token_amount_sum: {bigint} Total locked liquidity token amount (excluding skipped orders)
|
|
63
|
+
* - has_infinite_lp: {boolean} Whether includes infinite liquidity to minimum price
|
|
64
|
+
* - pass_order_id: {number} Index of skipped order in array (-1 if none skipped)
|
|
65
|
+
* - force_close_num: {number} Number of orders that need force closure for target sell amount
|
|
66
|
+
* - ideal_lp_sol_amount: {bigint} Theoretical maximum SOL obtainable at current price
|
|
67
|
+
* - real_lp_sol_amount: {bigint} Actual SOL obtainable considering real liquidity distribution
|
|
68
|
+
* - completion: {string} Sell completion percentage as decimal string (e.g., "85.2", "100.0")
|
|
69
|
+
* - slippage: {string} Price slippage percentage as decimal string (e.g., "2.5", "0.8")
|
|
70
|
+
* - suggestedTokenAmount: {string} Recommended token amount to sell based on available liquidity
|
|
71
|
+
* - suggestedSolAmount: {string} Expected SOL amount from suggested token sale
|
|
72
|
+
*/
|
|
73
|
+
async simulateTokenSell(mint, sellTokenAmount, passOrder = null, lastPrice = null, ordersData = null, curveData = null) {
|
|
74
|
+
return simulateTokenSell.call(this, mint, sellTokenAmount, passOrder, lastPrice, ordersData, curveData);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Simulate long position stop loss calculation
|
|
79
|
+
* @param {string} mint - Token address
|
|
80
|
+
* @param {bigint|string|number} buyTokenAmount - Token amount to buy for long position (u64 format, precision 10^9)
|
|
81
|
+
* @param {bigint|string|number} stopLossPrice - User desired stop loss price (u128 format)
|
|
82
|
+
* @param {Object|null} lastPrice - Token info, default null
|
|
83
|
+
* @param {Object|null} ordersData - Orders data, default null
|
|
84
|
+
* @returns {Promise<Object>} Stop loss analysis result
|
|
85
|
+
*/
|
|
86
|
+
async simulateLongStopLoss(mint, buyTokenAmount, stopLossPrice, lastPrice = null, ordersData = null, borrowFee = null) {
|
|
87
|
+
return simulateLongStopLoss.call(this, mint, buyTokenAmount, stopLossPrice, lastPrice, ordersData, borrowFee);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Simulate short position stop loss calculation
|
|
92
|
+
* @param {string} mint - Token address
|
|
93
|
+
* @param {bigint|string|number} sellTokenAmount - Token amount to sell for short position (u64 format, precision 10^9)
|
|
94
|
+
* @param {bigint|string|number} stopLossPrice - User desired stop loss price (u128 format)
|
|
95
|
+
* @param {Object|null} lastPrice - Token info, default null
|
|
96
|
+
* @param {Object|null} ordersData - Orders data, default null
|
|
97
|
+
* @returns {Promise<Object>} Stop loss analysis result
|
|
98
|
+
*/
|
|
99
|
+
async simulateShortStopLoss(mint, sellTokenAmount, stopLossPrice, lastPrice = null, ordersData = null, borrowFee = null) {
|
|
100
|
+
return simulateShortStopLoss.call(this, mint, sellTokenAmount, stopLossPrice, lastPrice, ordersData, borrowFee);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Simulate long position stop loss calculation with SOL amount input
|
|
105
|
+
* @param {string} mint - Token address
|
|
106
|
+
* @param {bigint|string|number} buySolAmount - SOL amount to spend for long position (u64 format, lamports)
|
|
107
|
+
* @param {bigint|string|number} stopLossPrice - User desired stop loss price (u128 format)
|
|
108
|
+
* @param {Object|null} lastPrice - Token info, default null
|
|
109
|
+
* @param {Object|null} ordersData - Orders data, default null
|
|
110
|
+
* @param {number} borrowFee - Borrow fee rate, default 2000 (2000/100000 = 0.02%)
|
|
111
|
+
* @returns {Promise<Object>} Stop loss analysis result (same as simulateLongStopLoss)
|
|
112
|
+
*/
|
|
113
|
+
async simulateLongSolStopLoss(mint, buySolAmount, stopLossPrice, lastPrice = null, ordersData = null, borrowFee = null, initialVirtualSol = null, initialVirtualToken = null, curveAccount = null) {
|
|
114
|
+
return simulateLongSolStopLoss.call(this, mint, buySolAmount, stopLossPrice, lastPrice, ordersData, borrowFee, initialVirtualSol, initialVirtualToken, curveAccount);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Simulate short position stop loss calculation with SOL amount input
|
|
119
|
+
* @param {string} mint - Token address
|
|
120
|
+
* @param {bigint|string|number} sellSolAmount - SOL amount needed for short position stop loss (u64 format, lamports)
|
|
121
|
+
* @param {bigint|string|number} stopLossPrice - User desired stop loss price (u128 format)
|
|
122
|
+
* @param {Object|null} lastPrice - Token info, default null
|
|
123
|
+
* @param {Object|null} ordersData - Orders data, default null
|
|
124
|
+
* @param {number} borrowFee - Borrow fee rate, default 2000 (2000/100000 = 0.02%)
|
|
125
|
+
* @returns {Promise<Object>} Stop loss analysis result (same as simulateShortStopLoss)
|
|
126
|
+
*/
|
|
127
|
+
async simulateShortSolStopLoss(mint, sellSolAmount, stopLossPrice, lastPrice = null, ordersData = null, borrowFee = null, initialVirtualSol = null, initialVirtualToken = null, curveAccount = null) {
|
|
128
|
+
return simulateShortSolStopLoss.call(this, mint, sellSolAmount, stopLossPrice, lastPrice, ordersData, borrowFee, initialVirtualSol, initialVirtualToken, curveAccount);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Generate candidate insertion indices for closing long position
|
|
133
|
+
* 为做多平仓生成候选插入索引
|
|
134
|
+
* @param {string} mint - Token address 代币地址
|
|
135
|
+
* @param {number|string|anchor.BN} closeOrderId - Order ID to close (order_id, not index) 要平仓的订单ID
|
|
136
|
+
* @param {Object|null} ordersData - Orders data (optional) 订单数据(可选)
|
|
137
|
+
* @returns {Promise<Object>} Result containing closeOrderIndices array 包含候选索引数组的结果
|
|
138
|
+
*/
|
|
139
|
+
async simulateLongClose(mint, closeOrderId, ordersData = null) {
|
|
140
|
+
return simulateLongClose.call(this, mint, closeOrderId, ordersData);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate candidate insertion indices for closing short position
|
|
145
|
+
* 为做空平仓生成候选插入索引
|
|
146
|
+
* @param {string} mint - Token address 代币地址
|
|
147
|
+
* @param {number|string|anchor.BN} closeOrderId - Order ID to close (order_id, not index) 要平仓的订单ID
|
|
148
|
+
* @param {Object|null} ordersData - Orders data (optional) 订单数据(可选)
|
|
149
|
+
* @returns {Promise<Object>} Result containing closeOrderIndices array 包含候选索引数组的结果
|
|
150
|
+
*/
|
|
151
|
+
async simulateShortClose(mint, closeOrderId, ordersData = null) {
|
|
152
|
+
return simulateShortClose.call(this, mint, closeOrderId, ordersData);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Simulate buy transaction with SOL amount input
|
|
157
|
+
* 模拟以 SOL 金额为输入的买入交易
|
|
158
|
+
* @param {string} mint - Token address 代币地址
|
|
159
|
+
* @param {bigint|string|number} buySolAmount - SOL amount to spend (u64 format, lamports)
|
|
160
|
+
* @returns {Promise<Object>} Buy simulation result with the following structure:
|
|
161
|
+
* - success: {boolean} Whether the simulation was successful
|
|
162
|
+
* - errorCode: {string|null} Error code if failed ('API_ERROR', 'DATA_ERROR', 'PARAM_ERROR')
|
|
163
|
+
* - errorMessage: {string|null} Error message if failed
|
|
164
|
+
* - data: {Object} Analysis result data containing:
|
|
165
|
+
* - inputType: {string} 'sol' - input type
|
|
166
|
+
* - inputAmount: {bigint} Input SOL amount
|
|
167
|
+
* - maxAllowedPrice: {bigint} Maximum allowed starting price (u128)
|
|
168
|
+
* - totalPriceSpan: {bigint} Total price range for the transaction (u128)
|
|
169
|
+
* - transactionCompletionRate: {number} Transaction completion rate (%)
|
|
170
|
+
* - idealTokenAmount: {bigint} Ideal token amount obtainable
|
|
171
|
+
* - idealSolAmount: {bigint} Ideal SOL amount needed
|
|
172
|
+
* - actualRequiredSolAmount: {bigint} Actual SOL amount required
|
|
173
|
+
* - actualObtainableTokenAmount: {bigint} Actual token amount obtainable
|
|
174
|
+
* - theoreticalSolAmount: {bigint} Theoretical SOL amount needed
|
|
175
|
+
* - minimumSlippagePercentage: {number} Minimum slippage percentage
|
|
176
|
+
* - totalLiquiditySolAmount: {bigint} Total available liquidity in SOL
|
|
177
|
+
* - totalLiquidityTokenAmount: {bigint} Total available liquidity in tokens
|
|
178
|
+
*/
|
|
179
|
+
async simulateBuy(mint, buySolAmount) {
|
|
180
|
+
try {
|
|
181
|
+
// Parameter validation
|
|
182
|
+
if (!mint || typeof mint !== 'string') {
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
errorCode: 'PARAM_ERROR',
|
|
186
|
+
errorMessage: 'Invalid mint parameter: must be a non-empty string',
|
|
187
|
+
data: null
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Convert buySolAmount to bigint
|
|
192
|
+
let solAmountBigInt;
|
|
193
|
+
try {
|
|
194
|
+
solAmountBigInt = typeof buySolAmount === 'bigint' ? buySolAmount : BigInt(buySolAmount);
|
|
195
|
+
if (solAmountBigInt <= 0n) {
|
|
196
|
+
throw new Error('Amount must be greater than 0');
|
|
197
|
+
}
|
|
198
|
+
} catch (error) {
|
|
199
|
+
return {
|
|
200
|
+
success: false,
|
|
201
|
+
errorCode: 'PARAM_ERROR',
|
|
202
|
+
errorMessage: `Invalid buySolAmount parameter: ${error.message}`,
|
|
203
|
+
data: null
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Get current price, orders data, and curve account in parallel
|
|
208
|
+
const [priceResult, ordersResult, upOrdersResult, curveAccount] = await Promise.all([
|
|
209
|
+
this.sdk.data.price(mint),
|
|
210
|
+
this.sdk.data.orders(mint, { type: 'down_orders' }),
|
|
211
|
+
this.sdk.data.orders(mint, { type: 'up_orders' }),
|
|
212
|
+
this.sdk.chain.getCurveAccount(mint, { skipBalances: true })
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
if (!priceResult || !ordersResult) {
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
errorCode: 'API_ERROR',
|
|
219
|
+
errorMessage: 'Failed to fetch price or orders data',
|
|
220
|
+
data: null
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Use simulateTokenBuy to calculate (approximate token amount first)
|
|
225
|
+
// This is a simplified implementation - you may need to iterate or use calcLiq directly
|
|
226
|
+
const currentPrice = typeof priceResult === 'string' ? BigInt(priceResult) : BigInt(priceResult.last_price || priceResult);
|
|
227
|
+
|
|
228
|
+
// Get curve account data for initialVirtualSol and initialVirtualToken
|
|
229
|
+
const initialVirtualSol = curveAccount.initialVirtualSol;
|
|
230
|
+
const initialVirtualToken = curveAccount.initialVirtualToken;
|
|
231
|
+
|
|
232
|
+
const reSolBuy = calcLiqSolBuy(currentPrice, buySolAmount, upOrdersResult.data.orders, 50, null, initialVirtualSol, initialVirtualToken);
|
|
233
|
+
|
|
234
|
+
//console.log("reSolBuy = ",reSolBuy)
|
|
235
|
+
|
|
236
|
+
const estimatedTokenAmount = reSolBuy.tokenAmount;
|
|
237
|
+
|
|
238
|
+
// Call simulateTokenBuy with estimated amount, pass curveAccount to avoid duplicate RPC
|
|
239
|
+
const tokenBuyResult = await this.simulateTokenBuy(mint, estimatedTokenAmount, null, priceResult, ordersResult, curveAccount);
|
|
240
|
+
|
|
241
|
+
// Transform result to match simulateBuy format
|
|
242
|
+
return {
|
|
243
|
+
success: true,
|
|
244
|
+
errorCode: null,
|
|
245
|
+
errorMessage: null,
|
|
246
|
+
data: {
|
|
247
|
+
inputType: 'sol',
|
|
248
|
+
inputAmount: solAmountBigInt,
|
|
249
|
+
maxAllowedPrice: currentPrice,
|
|
250
|
+
totalPriceSpan: tokenBuyResult.liqResult?.total_price_span || 0n,
|
|
251
|
+
transactionCompletionRate: parseFloat(tokenBuyResult.completion || '0'),
|
|
252
|
+
idealTokenAmount: estimatedTokenAmount,
|
|
253
|
+
idealSolAmount: solAmountBigInt,
|
|
254
|
+
actualRequiredSolAmount: tokenBuyResult.liqResult?.real_lp_sol_amount || solAmountBigInt,
|
|
255
|
+
actualObtainableTokenAmount: tokenBuyResult.liqResult?.free_lp_token_amount_sum || 0n,
|
|
256
|
+
theoreticalSolAmount: tokenBuyResult.liqResult?.ideal_lp_sol_amount || solAmountBigInt,
|
|
257
|
+
minimumSlippagePercentage: parseFloat(tokenBuyResult.slippage || '0'),
|
|
258
|
+
totalLiquiditySolAmount: tokenBuyResult.liqResult?.free_lp_sol_amount_sum || 0n,
|
|
259
|
+
totalLiquidityTokenAmount: tokenBuyResult.liqResult?.free_lp_token_amount_sum || 0n
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
errorCode: 'DATA_ERROR',
|
|
267
|
+
errorMessage: error.message || 'Unknown error occurred during buy simulation',
|
|
268
|
+
data: null
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Simulate sell transaction with token amount input
|
|
275
|
+
* 模拟以 Token 数量为输入的卖出交易
|
|
276
|
+
* @param {string} mint - Token address 代币地址
|
|
277
|
+
* @param {bigint|string|number} sellTokenAmount - Token amount to sell (u64 format, lamports)
|
|
278
|
+
* @returns {Promise<Object>} Sell simulation result with the following structure:
|
|
279
|
+
* - success: {boolean} Whether the simulation was successful
|
|
280
|
+
* - errorCode: {string|null} Error code if failed ('API_ERROR', 'DATA_ERROR', 'PARAM_ERROR')
|
|
281
|
+
* - errorMessage: {string|null} Error message if failed
|
|
282
|
+
* - data: {Object} Analysis result data containing:
|
|
283
|
+
* - inputType: {string} 'token' - input type
|
|
284
|
+
* - inputAmount: {bigint} Input token amount
|
|
285
|
+
* - minAllowedPrice: {bigint} Minimum allowed starting price (u128)
|
|
286
|
+
* - totalPriceSpan: {bigint} Total price range for the transaction (u128)
|
|
287
|
+
* - transactionCompletionRate: {number} Transaction completion rate (%)
|
|
288
|
+
* - idealSolAmount: {bigint} Ideal SOL amount obtainable
|
|
289
|
+
* - idealTokenAmount: {bigint} Ideal token amount to sell
|
|
290
|
+
* - actualObtainedSolAmount: {bigint} Actual SOL amount obtainable
|
|
291
|
+
* - actualConsumedTokenAmount: {bigint} Actual token amount consumed
|
|
292
|
+
* - theoreticalSolAmount: {bigint} Theoretical SOL amount obtainable
|
|
293
|
+
* - minimumSlippagePercentage: {number} Minimum slippage percentage
|
|
294
|
+
* - totalLiquiditySolAmount: {bigint} Total available liquidity in SOL
|
|
295
|
+
* - totalLiquidityTokenAmount: {bigint} Total available liquidity in tokens
|
|
296
|
+
*/
|
|
297
|
+
async simulateSell(mint, sellTokenAmount) {
|
|
298
|
+
try {
|
|
299
|
+
// Parameter validation
|
|
300
|
+
if (!mint || typeof mint !== 'string') {
|
|
301
|
+
return {
|
|
302
|
+
success: false,
|
|
303
|
+
errorCode: 'PARAM_ERROR',
|
|
304
|
+
errorMessage: 'Invalid mint parameter: must be a non-empty string',
|
|
305
|
+
data: null
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Convert sellTokenAmount to bigint
|
|
310
|
+
let tokenAmountBigInt;
|
|
311
|
+
try {
|
|
312
|
+
tokenAmountBigInt = typeof sellTokenAmount === 'bigint' ? sellTokenAmount : BigInt(sellTokenAmount);
|
|
313
|
+
if (tokenAmountBigInt <= 0n) {
|
|
314
|
+
throw new Error('Amount must be greater than 0');
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
return {
|
|
318
|
+
success: false,
|
|
319
|
+
errorCode: 'PARAM_ERROR',
|
|
320
|
+
errorMessage: `Invalid sellTokenAmount parameter: ${error.message}`,
|
|
321
|
+
data: null
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Get current price and orders data in parallel
|
|
326
|
+
// For sell transactions, we need down_orders (long orders that provide buy liquidity)
|
|
327
|
+
const [priceResult, ordersResult] = await Promise.all([
|
|
328
|
+
this.sdk.data.price(mint),
|
|
329
|
+
this.sdk.data.orders(mint, { type: 'down_orders' })
|
|
330
|
+
]);
|
|
331
|
+
|
|
332
|
+
if (!priceResult || !ordersResult) {
|
|
333
|
+
return {
|
|
334
|
+
success: false,
|
|
335
|
+
errorCode: 'API_ERROR',
|
|
336
|
+
errorMessage: 'Failed to fetch price or orders data',
|
|
337
|
+
data: null
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const currentPrice = typeof priceResult === 'string' ? BigInt(priceResult) : BigInt(priceResult.last_price || priceResult);
|
|
342
|
+
|
|
343
|
+
// Call simulateTokenSell
|
|
344
|
+
const tokenSellResult = await this.simulateTokenSell(mint, tokenAmountBigInt, null, priceResult, ordersResult);
|
|
345
|
+
|
|
346
|
+
// Estimate ideal SOL amount
|
|
347
|
+
const priceDecimal = CurveAMM.u128ToDecimal(currentPrice);
|
|
348
|
+
const tokenInDecimal = Number(tokenAmountBigInt) / 1e9; // Convert token lamports to tokens (9-digit precision)
|
|
349
|
+
const estimatedSolAmount = BigInt(Math.floor((tokenInDecimal * priceDecimal) * 1e9)); // Convert to SOL lamports
|
|
350
|
+
|
|
351
|
+
// Transform result to match simulateSell format
|
|
352
|
+
return {
|
|
353
|
+
success: true,
|
|
354
|
+
errorCode: null,
|
|
355
|
+
errorMessage: null,
|
|
356
|
+
data: {
|
|
357
|
+
inputType: 'token',
|
|
358
|
+
inputAmount: tokenAmountBigInt,
|
|
359
|
+
minAllowedPrice: currentPrice,
|
|
360
|
+
totalPriceSpan: tokenSellResult.liqResult?.total_price_span || 0n,
|
|
361
|
+
transactionCompletionRate: parseFloat(tokenSellResult.completion || '0'),
|
|
362
|
+
idealSolAmount: estimatedSolAmount,
|
|
363
|
+
idealTokenAmount: tokenAmountBigInt,
|
|
364
|
+
actualObtainedSolAmount: tokenSellResult.liqResult?.real_lp_sol_amount || 0n,
|
|
365
|
+
actualConsumedTokenAmount: tokenAmountBigInt,
|
|
366
|
+
theoreticalSolAmount: tokenSellResult.liqResult?.ideal_lp_sol_amount || estimatedSolAmount,
|
|
367
|
+
minimumSlippagePercentage: parseFloat(tokenSellResult.slippage || '0'),
|
|
368
|
+
totalLiquiditySolAmount: tokenSellResult.liqResult?.free_lp_sol_amount_sum || 0n,
|
|
369
|
+
totalLiquidityTokenAmount: tokenSellResult.liqResult?.free_lp_token_amount_sum || 0n
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
} catch (error) {
|
|
374
|
+
return {
|
|
375
|
+
success: false,
|
|
376
|
+
errorCode: 'DATA_ERROR',
|
|
377
|
+
errorMessage: error.message || 'Unknown error occurred during sell simulation',
|
|
378
|
+
data: null
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
module.exports = SimulatorModule;
|