100x-sdk 1.0.3 → 1.0.4

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.
@@ -2,14 +2,14 @@
2
2
  const CurveAMM = require('../../utils/curve_amm');
3
3
 
4
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|null} initialVirtualSol - 流动池SOL数量
12
- * @param {string|number|null} initialVirtualToken - 流动池Token数量
5
+ * Calculate the amount of Token obtainable when buying with a specified amount of SOL
6
+ * @param {bigint|string} price - Current trade price (u128 format)
7
+ * @param {bigint|string|number} buySolAmount - Amount of SOL to spend (lamports, 9-digit precision)
8
+ * @param {Array} orders - Array of orders locking liquidity
9
+ * @param {number} onceMaxOrder - Maximum number of orders per loop iteration
10
+ * @param {string|number|null} passOrderID - Order ID to skip (compared against the order_id field)
11
+ * @param {string|number|null} initialVirtualSol - Liquidity pool SOL amount
12
+ * @param {string|number|null} initialVirtualToken - Liquidity pool Token amount
13
13
  * @returns {Object} { tokenAmount: bigint, msg: string, closedOrdersCount: number }
14
14
  */
15
15
  function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID = null, initialVirtualSol = null, initialVirtualToken = null){
@@ -17,8 +17,8 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
17
17
 
18
18
  //console.log("calcLiqSolBuy: , price, buySolAmount, orders, onceMaxOrder, passOrderID , initialVirtualSol, initialVirtualToken=", price, buySolAmount, orders, onceMaxOrder, passOrderID , initialVirtualSol , initialVirtualToken);
19
19
 
20
- // 1. 参数验证
21
- // 转换为 bigint 以便比较
20
+ // 1. Parameter validation
21
+ // Convert to bigint for comparison
22
22
  let priceBigInt;
23
23
  let buySolAmountBigInt;
24
24
 
@@ -33,7 +33,7 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
33
33
  };
34
34
  }
35
35
 
36
- // 检查价格和金额是否有效
36
+ // Check whether price and amount are valid
37
37
  if (priceBigInt <= 0n) {
38
38
  return {
39
39
  tokenAmount: 0n,
@@ -50,7 +50,7 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
50
50
  };
51
51
  }
52
52
 
53
- // 2. 设置默认流动池参数
53
+ // 2. Set default liquidity pool parameters
54
54
  const Decimal = require('decimal.js');
55
55
  const virtualSol = initialVirtualSol !== null
56
56
  ? new Decimal(initialVirtualSol.toString()).div(CurveAMM.SOL_PRECISION_FACTOR_DECIMAL)
@@ -62,9 +62,9 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
62
62
  //console.log("calcLiqSolBuy: virtualSol,virtualToken=",virtualSol,virtualToken)
63
63
 
64
64
 
65
- // 3. 处理空订单情况(第一阶段)
65
+ // 3. Handle the empty orders case (first stage)
66
66
  if (!orders || orders.length === 0) {
67
- // 直接计算完整流动性下的买入
67
+ // Directly calculate the buy under full liquidity
68
68
  const result = CurveAMM.buyFromPriceWithSolInputWithParams(
69
69
  price,
70
70
  buySolAmount,
@@ -88,16 +88,16 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
88
88
  };
89
89
  }
90
90
 
91
- // 4. 处理有订单的情况(第二阶段:分段流动性计算)
91
+ // 4. Handle the case with orders (second stage: segmented liquidity calculation)
92
92
 
93
- // 初始化变量
94
- let currentPrice = priceBigInt; // 当前价格指针
95
- let remainingSol = buySolAmountBigInt; // 剩余可用 SOL
96
- let totalTokenAmount = 0n; // 累计获得的 token
97
- let closedOrdersCount = 0; // 平仓订单数量
98
- let processedOrders = 0; // 已处理订单数
93
+ // Initialize variables
94
+ let currentPrice = priceBigInt; // Current price pointer
95
+ let remainingSol = buySolAmountBigInt; // Remaining available SOL
96
+ let totalTokenAmount = 0n; // Accumulated tokens obtained
97
+ let closedOrdersCount = 0; // Number of closed orders
98
+ let processedOrders = 0; // Number of processed orders
99
99
 
100
- // 检查当前价格是否高于第一个订单的结束价格
100
+ // Check whether the current price is higher than the first order's end price
101
101
  if (orders.length > 0) {
102
102
  const firstOrderEndPrice = typeof orders[0].lock_lp_end_price === 'bigint'
103
103
  ? orders[0].lock_lp_end_price
@@ -112,23 +112,23 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
112
112
  }
113
113
  }
114
114
 
115
- // 遍历订单(最多 onceMaxOrder 个)
115
+ // Iterate over orders (up to onceMaxOrder)
116
116
  for (let i = 0; i < orders.length && processedOrders < onceMaxOrder; i++) {
117
117
  const order = orders[i];
118
118
 
119
- // 检查是否需要跳过此订单
119
+ // Check whether this order needs to be skipped
120
120
  if (passOrderID !== null && order.order_id !== undefined) {
121
- // 将两者都转换为字符串进行比较
121
+ // Convert both to strings for comparison
122
122
  const orderIdStr = String(order.order_id);
123
123
  const passOrderIdStr = String(passOrderID);
124
124
 
125
125
  if (orderIdStr === passOrderIdStr) {
126
- // 跳过此订单,不处理其锁定区间,继续下一个订单
126
+ // Skip this order, do not process its lock range, continue to the next order
127
127
  continue;
128
128
  }
129
129
  }
130
130
 
131
- // 转换订单价格为 bigint
131
+ // Convert order prices to bigint
132
132
  let lockStartPrice, lockEndPrice;
133
133
  try {
134
134
  lockStartPrice = typeof order.lock_lp_start_price === 'bigint'
@@ -145,9 +145,9 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
145
145
  };
146
146
  }
147
147
 
148
- // 步骤1:计算可用区间(currentPrice → lockStartPrice)
148
+ // Step 1: Calculate the available range (currentPrice → lockStartPrice)
149
149
  if (currentPrice < lockStartPrice) {
150
- // 1.1 计算这段区间需要多少 SOL 和能获得多少 token
150
+ // 1.1 Calculate how much SOL this range needs and how many tokens can be obtained
151
151
  const result = CurveAMM.buyFromPriceToPriceWithParams(
152
152
  currentPrice,
153
153
  lockStartPrice,
@@ -155,7 +155,7 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
155
155
  virtualToken
156
156
  );
157
157
 
158
- // 检查计算是否成功
158
+ // Check whether the calculation succeeded
159
159
  if (result === null) {
160
160
  return {
161
161
  tokenAmount: 0n,
@@ -166,14 +166,14 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
166
166
 
167
167
  const [solNeeded, tokenGained] = result;
168
168
 
169
- // 1.2 判断剩余 SOL 是否足够
169
+ // 1.2 Determine whether the remaining SOL is sufficient
170
170
  if (remainingSol >= solNeeded) {
171
- // 足够:买完这段区间,继续下一段
171
+ // Sufficient: buy through this range and continue to the next segment
172
172
  remainingSol -= solNeeded;
173
173
  totalTokenAmount += tokenGained;
174
174
  currentPrice = lockStartPrice;
175
175
  } else {
176
- // 不够:用完剩余 SOL,计算能买多少,然后返回
176
+ // Insufficient: use up the remaining SOL, calculate how much can be bought, then return
177
177
  const finalResult = CurveAMM.buyFromPriceWithSolInputWithParams(
178
178
  currentPrice,
179
179
  remainingSol,
@@ -200,15 +200,15 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
200
200
  }
201
201
  }
202
202
 
203
- // 步骤2:跳过锁定区间(lockStartPrice → lockEndPrice)
203
+ // Step 2: Skip the lock range (lockStartPrice → lockEndPrice)
204
204
  currentPrice = lockEndPrice;
205
205
  processedOrders++;
206
206
 
207
- // 步骤3:判断是否平仓
208
- // 如果价格到达 lockEndPrice,说明这个订单被平仓
207
+ // Step 3: Determine whether the order is closed
208
+ // If the price reaches lockEndPrice, this order is closed
209
209
  closedOrdersCount++;
210
210
 
211
- // 检查 SOL 是否已用完
211
+ // Check whether SOL has been used up
212
212
  if (remainingSol === 0n) {
213
213
  return {
214
214
  tokenAmount: totalTokenAmount,
@@ -218,8 +218,8 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
218
218
  }
219
219
  }
220
220
 
221
- // 步骤4:处理最后的无限流动性区间
222
- // 所有订单处理完后,用剩余 SOL 继续买入
221
+ // Step 4: Handle the final infinite liquidity range
222
+ // After all orders are processed, continue buying with the remaining SOL
223
223
  if (remainingSol > 0n) {
224
224
  const finalResult = CurveAMM.buyFromPriceWithSolInputWithParams(
225
225
  currentPrice,
@@ -246,7 +246,7 @@ function calcLiqSolBuy(price, buySolAmount, orders, onceMaxOrder, passOrderID =
246
246
  };
247
247
  }
248
248
 
249
- // 步骤5:SOL 刚好用完
249
+ // Step 5: SOL is exactly used up
250
250
  return {
251
251
  tokenAmount: totalTokenAmount,
252
252
  msg: `SOL刚好用完,最终价格: ${currentPrice.toString()}`,
@@ -7,12 +7,11 @@ const CANDIDATE_NODES_EACH_SIDE = Math.floor((MAX_CANDIDATE_INDICES - 1) / 2);
7
7
  const NO_ORDER = 65535;
8
8
 
9
9
  /**
10
- * 根据 index 在订单数组中查找订单
11
10
  * Find order in array by its index field
12
11
  *
13
- * @param {Array} orders - 订单数组 / Orders array
14
- * @param {number} index - 订单的 index 字段值 / Order's index field value
15
- * @returns {Object|null} 找到的订单对象,找不到返回 null / Found order object or null
12
+ * @param {Array} orders - Orders array
13
+ * @param {number} index - Order's index field value
14
+ * @returns {Object|null} Found order object or null
16
15
  */
17
16
  function findOrderByIndex(orders, index) {
18
17
  for (let i = 0; i < orders.length; i++) {
@@ -24,28 +23,27 @@ function findOrderByIndex(orders, index) {
24
23
  }
25
24
 
26
25
  /**
27
- * 为做多平仓生成候选插入索引
28
26
  * Generate candidate insertion indices for closing long position
29
27
  *
30
- * @param {string} mint - 代币地址 / Token address
31
- * @param {number|string|anchor.BN} closeOrderId - 要平仓的订单ID (order_id, 不是 index) / Order ID to close (order_id, not index)
32
- * @param {Object|null} ordersData - 订单数据(可选,如果不提供会自动获取)/ Orders data (optional, will fetch if not provided)
33
- * @returns {Promise<Object>} 返回包含候选索引数组的对象 / Returns object containing candidate indices array
34
- * - closeOrderIndices: {number[]} 候选插入位置索引数组 / Candidate insertion position indices array
28
+ * @param {string} mint - Token address
29
+ * @param {number|string|anchor.BN} closeOrderId - Order ID to close (order_id, not index)
30
+ * @param {Object|null} ordersData - Orders data (optional, will fetch if not provided)
31
+ * @returns {Promise<Object>} Returns object containing candidate indices array
32
+ * - closeOrderIndices: {number[]} Candidate insertion position indices array
35
33
  *
36
- * @throws {Error} 如果找不到对应的 closeOrderId / If closeOrderId is not found
34
+ * @throws {Error} If closeOrderId is not found
37
35
  *
38
36
  * @example
39
- * // 平仓做多订单
37
+ * // Close a long position order
40
38
  * const result = await sdk.simulator.simulateLongClose(
41
39
  * 'HG9R8CE9N18U8zYqo6cqS4bFaCAzHbAhaAe1zq8Hq7PF',
42
40
  * 1090 // order_id
43
41
  * );
44
- * console.log('候选索引:', result.closeOrderIndices);
45
- * // 输出: { closeOrderIndices: [25, 15, 35, 5, 45, ...] }
42
+ * console.log('Candidate indices:', result.closeOrderIndices);
43
+ * // Output: { closeOrderIndices: [25, 15, 35, 5, 45, ...] }
46
44
  */
47
45
  async function simulateLongClose(mint, closeOrderId, ordersData = null) {
48
- // 1. 获取 down_orders 数据(做多订单在 down_orders 中)
46
+ // 1. Fetch down_orders data (long orders are in down_orders)
49
47
  if (!ordersData) {
50
48
  ordersData = await this.sdk.data.orders(mint, { type: 'down_orders' });
51
49
  }
@@ -56,10 +54,10 @@ async function simulateLongClose(mint, closeOrderId, ordersData = null) {
56
54
 
57
55
  const orders = ordersData.data.orders;
58
56
 
59
- // 2. 将 closeOrderId 转换为字符串(因为 API 返回的 order_id 是字符串)
57
+ // 2. Convert closeOrderId to string (since order_id returned by the API is a string)
60
58
  const targetOrderId = closeOrderId.toString();
61
59
 
62
- // 3. 在订单列表中查找匹配的订单
60
+ // 3. Find the matching order in the order list
63
61
  let targetOrderIndex = -1;
64
62
  for (let i = 0; i < orders.length; i++) {
65
63
  if (orders[i].order_id === targetOrderId) {
@@ -68,78 +66,77 @@ async function simulateLongClose(mint, closeOrderId, ordersData = null) {
68
66
  }
69
67
  }
70
68
 
71
- // 4. 如果找不到订单,抛出错误
69
+ // 4. If the order is not found, throw an error
72
70
  if (targetOrderIndex === -1) {
73
71
  throw new Error(`Order with order_id ${targetOrderId} not found in down_orders`);
74
72
  }
75
73
 
76
- // 5. 获取目标订单的 OrderBook index
74
+ // 5. Get the OrderBook index of the target order
77
75
  const targetOrder = orders[targetOrderIndex];
78
76
  const mainIndex = targetOrder.index;
79
77
 
80
- // 6. 生成候选索引数组(通过链表结构遍历前后节点)
78
+ // 6. Generate the candidate indices array (traverse prev/next nodes via the linked list structure)
81
79
  const indices = [];
82
80
 
83
- // 添加主位置
81
+ // Add the main position
84
82
  indices.push(mainIndex);
85
83
 
86
- // 通过链表结构添加前后节点的索引
84
+ // Add indices of prev/next nodes via the linked list structure
87
85
  let prevNode = targetOrder;
88
86
  let nextNode = targetOrder;
89
87
 
90
88
  for (let offset = 1; offset <= CANDIDATE_NODES_EACH_SIDE; offset++) {
91
- // 添加前面第 offset 个节点(通过 prev_order 链表指针)
89
+ // Add the offset-th preceding node (via the prev_order linked list pointer)
92
90
  if (prevNode.prev_order !== NO_ORDER) {
93
91
  const prevOrder = findOrderByIndex(orders, prevNode.prev_order);
94
92
  if (prevOrder && prevOrder.index !== undefined) {
95
93
  indices.push(prevOrder.index);
96
- prevNode = prevOrder; // 继续向前遍历
94
+ prevNode = prevOrder; // Continue traversing backward
97
95
  } else {
98
- prevNode = { prev_order: NO_ORDER }; // 找不到则停止
96
+ prevNode = { prev_order: NO_ORDER }; // Stop if not found
99
97
  }
100
98
  }
101
99
 
102
- // 添加后面第 offset 个节点(通过 next_order 链表指针)
100
+ // Add the offset-th following node (via the next_order linked list pointer)
103
101
  if (nextNode.next_order !== NO_ORDER) {
104
102
  const nextOrder = findOrderByIndex(orders, nextNode.next_order);
105
103
  if (nextOrder && nextOrder.index !== undefined) {
106
104
  indices.push(nextOrder.index);
107
- nextNode = nextOrder; // 继续向后遍历
105
+ nextNode = nextOrder; // Continue traversing forward
108
106
  } else {
109
- nextNode = { next_order: NO_ORDER }; // 找不到则停止
107
+ nextNode = { next_order: NO_ORDER }; // Stop if not found
110
108
  }
111
109
  }
112
110
  }
113
111
 
114
- // 7. 返回结果
112
+ // 7. Return the result
115
113
  return {
116
114
  closeOrderIndices: indices
117
115
  };
118
116
  }
119
117
 
120
118
  /**
121
- * 为做空平仓生成候选插入索引
122
119
  * Generate candidate insertion indices for closing short position
123
120
  *
124
- * @param {string} mint - 代币地址 / Token address
125
- * @param {number|string|anchor.BN} closeOrderId - 要平仓的订单ID (order_id, 不是 index) / Order ID to close (order_id, not index)
126
- * @param {Object|null} ordersData - 订单数据(可选,如果不提供会自动获取)/ Orders data (optional, will fetch if not provided)
127
- * @returns {Promise<Object>} 返回包含候选索引数组的对象 / Returns object containing candidate indices array
128
- * - closeOrderIndices: {number[]} 候选插入位置索引数组 / Candidate insertion position indices array
121
+ * @param {string} mint - Token address
122
+ * @param {number|string|anchor.BN} closeOrderId - Order ID to close (order_id, not index)
123
+ * @param {Object|null} ordersData - Orders data (optional, will fetch if not provided)
124
+ * @returns {Promise<Object>} Returns object containing candidate indices array
125
+ * - closeOrderIndices: {number[]} Candidate insertion position indices array
129
126
  *
130
- * @throws {Error} 如果找不到对应的 closeOrderId / If closeOrderId is not found
127
+ * @throws {Error} If closeOrderId is not found
131
128
  *
132
129
  * @example
133
- * // 平仓做空订单
130
+ * // Close a short position order
134
131
  * const result = await sdk.simulator.simulateShortClose(
135
132
  * 'HG9R8CE9N18U8zYqo6cqS4bFaCAzHbAhaAe1zq8Hq7PF',
136
133
  * 1090 // order_id
137
134
  * );
138
- * console.log('候选索引:', result.closeOrderIndices);
139
- * // 输出: { closeOrderIndices: [25, 15, 35, 5, 45, ...] }
135
+ * console.log('Candidate indices:', result.closeOrderIndices);
136
+ * // Output: { closeOrderIndices: [25, 15, 35, 5, 45, ...] }
140
137
  */
141
138
  async function simulateShortClose(mint, closeOrderId, ordersData = null) {
142
- // 1. 获取 up_orders 数据(做空订单在 up_orders 中)
139
+ // 1. Fetch up_orders data (short orders are in up_orders)
143
140
  if (!ordersData) {
144
141
  ordersData = await this.sdk.data.orders(mint, { type: 'up_orders' });
145
142
  }
@@ -150,10 +147,10 @@ async function simulateShortClose(mint, closeOrderId, ordersData = null) {
150
147
 
151
148
  const orders = ordersData.data.orders;
152
149
 
153
- // 2. 将 closeOrderId 转换为字符串(因为 API 返回的 order_id 是字符串)
150
+ // 2. Convert closeOrderId to string (since order_id returned by the API is a string)
154
151
  const targetOrderId = closeOrderId.toString();
155
152
 
156
- // 3. 在订单列表中查找匹配的订单
153
+ // 3. Find the matching order in the order list
157
154
  let targetOrderIndex = -1;
158
155
  for (let i = 0; i < orders.length; i++) {
159
156
  if (orders[i].order_id === targetOrderId) {
@@ -162,50 +159,50 @@ async function simulateShortClose(mint, closeOrderId, ordersData = null) {
162
159
  }
163
160
  }
164
161
 
165
- // 4. 如果找不到订单,抛出错误
162
+ // 4. If the order is not found, throw an error
166
163
  if (targetOrderIndex === -1) {
167
164
  throw new Error(`Order with order_id ${targetOrderId} not found in up_orders`);
168
165
  }
169
166
 
170
- // 5. 获取目标订单的 OrderBook index
167
+ // 5. Get the OrderBook index of the target order
171
168
  const targetOrder = orders[targetOrderIndex];
172
169
  const mainIndex = targetOrder.index;
173
170
 
174
- // 6. 生成候选索引数组(通过链表结构遍历前后节点)
171
+ // 6. Generate the candidate indices array (traverse prev/next nodes via the linked list structure)
175
172
  const indices = [];
176
173
 
177
- // 添加主位置
174
+ // Add the main position
178
175
  indices.push(mainIndex);
179
176
 
180
- // 通过链表结构添加前后节点的索引
177
+ // Add indices of prev/next nodes via the linked list structure
181
178
  let prevNode = targetOrder;
182
179
  let nextNode = targetOrder;
183
180
 
184
181
  for (let offset = 1; offset <= CANDIDATE_NODES_EACH_SIDE; offset++) {
185
- // 添加前面第 offset 个节点(通过 prev_order 链表指针)
182
+ // Add the offset-th preceding node (via the prev_order linked list pointer)
186
183
  if (prevNode.prev_order !== NO_ORDER) {
187
184
  const prevOrder = findOrderByIndex(orders, prevNode.prev_order);
188
185
  if (prevOrder && prevOrder.index !== undefined) {
189
186
  indices.push(prevOrder.index);
190
- prevNode = prevOrder; // 继续向前遍历
187
+ prevNode = prevOrder; // Continue traversing backward
191
188
  } else {
192
- prevNode = { prev_order: NO_ORDER }; // 找不到则停止
189
+ prevNode = { prev_order: NO_ORDER }; // Stop if not found
193
190
  }
194
191
  }
195
192
 
196
- // 添加后面第 offset 个节点(通过 next_order 链表指针)
193
+ // Add the offset-th following node (via the next_order linked list pointer)
197
194
  if (nextNode.next_order !== NO_ORDER) {
198
195
  const nextOrder = findOrderByIndex(orders, nextNode.next_order);
199
196
  if (nextOrder && nextOrder.index !== undefined) {
200
197
  indices.push(nextOrder.index);
201
- nextNode = nextOrder; // 继续向后遍历
198
+ nextNode = nextOrder; // Continue traversing forward
202
199
  } else {
203
- nextNode = { next_order: NO_ORDER }; // 找不到则停止
200
+ nextNode = { next_order: NO_ORDER }; // Stop if not found
204
201
  }
205
202
  }
206
203
  }
207
204
 
208
- // 7. 返回结果
205
+ // 7. Return the result
209
206
  return {
210
207
  closeOrderIndices: indices
211
208
  };