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.
- package/dist/100x-sdk.cjs.js +6450 -3903
- package/dist/100x-sdk.esm.js +5683 -3373
- package/dist/100x-sdk.js +5683 -3373
- package/dist/100x-sdk.js.map +1 -1
- package/dist/index.d.ts +19 -19
- package/package.json +1 -1
- package/src/modules/chain.js +26 -26
- package/src/modules/fast.js +88 -88
- package/src/modules/param.js +6 -6
- package/src/modules/simulator/buy_sell_token.js +38 -39
- package/src/modules/simulator/calcLiq.js +176 -198
- package/src/modules/simulator/calc_sol_liq.js +40 -40
- package/src/modules/simulator/close_indices.js +51 -54
- package/src/modules/simulator/long_shrot_stop.js +332 -332
- package/src/modules/simulator/stop_loss_utils.js +125 -125
- package/src/modules/simulator/utils.js +1 -2
- package/src/modules/simulator.js +14 -19
- package/src/modules/token.js +69 -69
- package/src/modules/tools.js +1 -1
- package/src/modules/trading.js +97 -97
- package/src/sdk.js +22 -23
- package/src/types/index.d.ts +19 -19
- package/src/utils/constants.js +2 -2
- package/src/utils/curve_amm.js +54 -54
- package/src/utils/orderUtils.js +1 -3
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
const CurveAMM = require('../../utils/curve_amm');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {bigint|string} price -
|
|
7
|
-
* @param {bigint|string|number} buySolAmount -
|
|
8
|
-
* @param {Array} orders -
|
|
9
|
-
* @param {number} onceMaxOrder -
|
|
10
|
-
* @param {string|number|null} passOrderID -
|
|
11
|
-
* @param {string|number|null} initialVirtualSol -
|
|
12
|
-
* @param {string|number|null} initialVirtualToken -
|
|
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
|
-
//
|
|
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; //
|
|
96
|
-
let totalTokenAmount = 0n; //
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
148
|
+
// Step 1: Calculate the available range (currentPrice → lockStartPrice)
|
|
149
149
|
if (currentPrice < lockStartPrice) {
|
|
150
|
-
// 1.1
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
203
|
+
// Step 2: Skip the lock range (lockStartPrice → lockEndPrice)
|
|
204
204
|
currentPrice = lockEndPrice;
|
|
205
205
|
processedOrders++;
|
|
206
206
|
|
|
207
|
-
//
|
|
208
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
222
|
-
//
|
|
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
|
-
//
|
|
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 -
|
|
14
|
-
* @param {number} index -
|
|
15
|
-
* @returns {Object|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 -
|
|
31
|
-
* @param {number|string|anchor.BN} closeOrderId -
|
|
32
|
-
* @param {Object|null} ordersData -
|
|
33
|
-
* @returns {Promise<Object>}
|
|
34
|
-
* - closeOrderIndices: {number[]}
|
|
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}
|
|
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('
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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 -
|
|
125
|
-
* @param {number|string|anchor.BN} closeOrderId -
|
|
126
|
-
* @param {Object|null} ordersData -
|
|
127
|
-
* @returns {Promise<Object>}
|
|
128
|
-
* - closeOrderIndices: {number[]}
|
|
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}
|
|
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('
|
|
139
|
-
* //
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
};
|