dexbot 1.4.3 → 1.4.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/modules/dexbot_cow_runtime.d.ts +30 -0
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +192 -0
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +31 -25
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/order/accounting.d.ts +2 -2
- package/dist/modules/order/accounting.d.ts.map +1 -1
- package/dist/modules/order/accounting.js +3 -6
- package/dist/modules/order/accounting.js.map +1 -1
- package/dist/modules/order/grid.d.ts +1 -1
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +34 -35
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile.d.ts +3 -9
- package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile.js +80 -48
- package/dist/modules/order/grid_reconcile.js.map +1 -1
- package/dist/modules/order/manager.d.ts +38 -7
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +83 -121
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/strategy.js +0 -1
- package/dist/modules/order/strategy.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +1 -2
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +26 -1
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +91 -53
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/order.d.ts.map +1 -1
- package/dist/modules/order/utils/order.js +10 -20
- package/dist/modules/order/utils/order.js.map +1 -1
- package/dist/modules/order/utils/system.d.ts +8 -3
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +23 -62
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/order/utils/validate.js +1 -1
- package/dist/modules/order/utils/validate.js.map +1 -1
- package/package.json +1 -1
|
@@ -268,6 +268,34 @@ declare function buildCowResultFromPlan(bot: any, plan: any): {
|
|
|
268
268
|
* @param {Set<string>} skippedSlotIds
|
|
269
269
|
* @param {number} [skippedCount=0]
|
|
270
270
|
*/
|
|
271
|
+
/**
|
|
272
|
+
* Pre-apply rotation state transitions to the working grid before commit.
|
|
273
|
+
* This makes the COW commit truly atomic for structural changes — source slots
|
|
274
|
+
* are cleared to VIRTUAL and destination slots are activated with the inherited
|
|
275
|
+
* orderId before the working grid is committed to master, eliminating the need
|
|
276
|
+
* for post-commit structural patching in processBatchResults.
|
|
277
|
+
*
|
|
278
|
+
* Only slot-to-slot rotations (newGridId exists) need pre-application;
|
|
279
|
+
* in-place rotations already have their size/price changes in the working grid.
|
|
280
|
+
*/
|
|
281
|
+
declare function applyRotationTransitionsToWorkingGrid(bot: any, workingGrid: any, executedContexts: any): void;
|
|
282
|
+
/**
|
|
283
|
+
* Poll the chain after an uncertain broadcast to check if CREATE operations
|
|
284
|
+
* were actually accepted. Uses fingerprint matching against readOpenOrders.
|
|
285
|
+
* Falls back to reconciliation if polling cannot confirm within retries.
|
|
286
|
+
*
|
|
287
|
+
* We specifically confirm CREATE operations because they leave a detectable
|
|
288
|
+
* footprint on the chain (new order with matching fingerprint). UPDATEs and
|
|
289
|
+
* CANCELs modify existing orders and cannot be reliably distinguished from
|
|
290
|
+
* "not yet visible" state by simple polling.
|
|
291
|
+
*
|
|
292
|
+
* @returns {{ allConfirmed: boolean, confirmed: Array, unconfirmed: Array }}
|
|
293
|
+
*/
|
|
294
|
+
declare function pollChainForConfirmation(bot: any, opContexts: any, options?: any): Promise<{
|
|
295
|
+
allConfirmed: boolean;
|
|
296
|
+
confirmed: any[];
|
|
297
|
+
unconfirmed: any[];
|
|
298
|
+
}>;
|
|
271
299
|
declare function restoreSkippedUpdateSlotsInWorkingGrid(bot: any, workingGrid: any, skippedSlotIds: any, skippedCount?: any): void;
|
|
272
300
|
/**
|
|
273
301
|
* COW broadcast: Execute blockchain operations and commit working grid on success.
|
|
@@ -315,6 +343,8 @@ declare const _default: {
|
|
|
315
343
|
buildActionsFromPlan: typeof buildActionsFromPlan;
|
|
316
344
|
buildCowResultFromPlan: typeof buildCowResultFromPlan;
|
|
317
345
|
restoreSkippedUpdateSlotsInWorkingGrid: typeof restoreSkippedUpdateSlotsInWorkingGrid;
|
|
346
|
+
applyRotationTransitionsToWorkingGrid: typeof applyRotationTransitionsToWorkingGrid;
|
|
347
|
+
pollChainForConfirmation: typeof pollChainForConfirmation;
|
|
318
348
|
updateOrdersOnChainBatchCOW: typeof updateOrdersOnChainBatchCOW;
|
|
319
349
|
processBatchResults: typeof processBatchResults;
|
|
320
350
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dexbot_cow_runtime.d.ts","sourceRoot":"","sources":["../../modules/dexbot_cow_runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dexbot_cow_runtime.d.ts","sourceRoot":"","sources":["../../modules/dexbot_cow_runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1107,6 +1107,142 @@ function buildCowResultFromPlan(bot, plan) {
|
|
|
1107
1107
|
* @param {Set<string>} skippedSlotIds
|
|
1108
1108
|
* @param {number} [skippedCount=0]
|
|
1109
1109
|
*/
|
|
1110
|
+
/**
|
|
1111
|
+
* Pre-apply rotation state transitions to the working grid before commit.
|
|
1112
|
+
* This makes the COW commit truly atomic for structural changes — source slots
|
|
1113
|
+
* are cleared to VIRTUAL and destination slots are activated with the inherited
|
|
1114
|
+
* orderId before the working grid is committed to master, eliminating the need
|
|
1115
|
+
* for post-commit structural patching in processBatchResults.
|
|
1116
|
+
*
|
|
1117
|
+
* Only slot-to-slot rotations (newGridId exists) need pre-application;
|
|
1118
|
+
* in-place rotations already have their size/price changes in the working grid.
|
|
1119
|
+
*/
|
|
1120
|
+
function applyRotationTransitionsToWorkingGrid(bot, workingGrid, executedContexts) {
|
|
1121
|
+
if (!workingGrid || !executedContexts)
|
|
1122
|
+
return;
|
|
1123
|
+
for (const ctx of executedContexts) {
|
|
1124
|
+
if (ctx.kind !== 'rotation' || !ctx.rotation?.newGridId)
|
|
1125
|
+
continue;
|
|
1126
|
+
const { rotation } = ctx;
|
|
1127
|
+
const { oldOrder, newGridId, newPrice, newSize, type } = rotation;
|
|
1128
|
+
// Source slot → VIRTUAL (if it's a different slot)
|
|
1129
|
+
if (oldOrder?.id && oldOrder.id !== newGridId) {
|
|
1130
|
+
const sourceSlot = workingGrid.get(oldOrder.id);
|
|
1131
|
+
if (sourceSlot && sourceSlot.orderId) {
|
|
1132
|
+
workingGrid.set(oldOrder.id, {
|
|
1133
|
+
...sourceSlot,
|
|
1134
|
+
state: ORDER_STATES.VIRTUAL,
|
|
1135
|
+
orderId: null,
|
|
1136
|
+
rawOnChain: null
|
|
1137
|
+
});
|
|
1138
|
+
bot.manager.logger.log(`[COW] Pre-applied rotation: source ${oldOrder.id} → VIRTUAL (order ${sourceSlot.orderId} moved to ${newGridId})`, 'debug');
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
// Destination slot → ACTIVE with inherited orderId from source
|
|
1142
|
+
const destSlot = workingGrid.get(newGridId);
|
|
1143
|
+
if (destSlot) {
|
|
1144
|
+
workingGrid.set(newGridId, {
|
|
1145
|
+
...destSlot,
|
|
1146
|
+
id: newGridId,
|
|
1147
|
+
type,
|
|
1148
|
+
size: newSize,
|
|
1149
|
+
price: newPrice,
|
|
1150
|
+
state: ORDER_STATES.ACTIVE,
|
|
1151
|
+
// oldOrder?.orderId is the authoritative source: the rotation
|
|
1152
|
+
// moved this orderId from the source slot. destSlot.orderId
|
|
1153
|
+
// is only a fallback for edge cases where the destination
|
|
1154
|
+
// already held a prior committed ID (e.g. a partial commit
|
|
1155
|
+
// left a stale reference). The source-of-truth is always the
|
|
1156
|
+
// original order being rotated.
|
|
1157
|
+
orderId: oldOrder?.orderId || destSlot.orderId || null
|
|
1158
|
+
});
|
|
1159
|
+
bot.manager.logger.log(`[COW] Pre-applied rotation: dest ${newGridId} → ACTIVE (orderId=${oldOrder?.orderId || destSlot.orderId || 'none'})`, 'debug');
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Sleep for a given number of milliseconds.
|
|
1165
|
+
*/
|
|
1166
|
+
function sleep(ms) {
|
|
1167
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Poll the chain after an uncertain broadcast to check if CREATE operations
|
|
1171
|
+
* were actually accepted. Uses fingerprint matching against readOpenOrders.
|
|
1172
|
+
* Falls back to reconciliation if polling cannot confirm within retries.
|
|
1173
|
+
*
|
|
1174
|
+
* We specifically confirm CREATE operations because they leave a detectable
|
|
1175
|
+
* footprint on the chain (new order with matching fingerprint). UPDATEs and
|
|
1176
|
+
* CANCELs modify existing orders and cannot be reliably distinguished from
|
|
1177
|
+
* "not yet visible" state by simple polling.
|
|
1178
|
+
*
|
|
1179
|
+
* @returns {{ allConfirmed: boolean, confirmed: Array, unconfirmed: Array }}
|
|
1180
|
+
*/
|
|
1181
|
+
async function pollChainForConfirmation(bot, opContexts, options = {}) {
|
|
1182
|
+
const maxPollRetries = options.maxPollRetries || 4;
|
|
1183
|
+
const pollIntervalMs = options.pollIntervalMs || 1500;
|
|
1184
|
+
// Only CREATE operations can be confirmed by polling (they appear as new orders on chain)
|
|
1185
|
+
const createContexts = opContexts.filter((ctx) => ctx && ctx.kind === 'create' && ctx.finalInts && ctx.order);
|
|
1186
|
+
if (createContexts.length === 0) {
|
|
1187
|
+
return { allConfirmed: false, confirmed: [], unconfirmed: [...opContexts] };
|
|
1188
|
+
}
|
|
1189
|
+
const accountRef = bot.accountId || bot.account?.id || bot.account;
|
|
1190
|
+
let remaining = [...createContexts];
|
|
1191
|
+
for (let attempt = 1; attempt <= maxPollRetries; attempt++) {
|
|
1192
|
+
try {
|
|
1193
|
+
const chainSnapshot = await chainOrders.readOpenOrders(accountRef);
|
|
1194
|
+
if (!Array.isArray(chainSnapshot) || chainSnapshot.length === 0) {
|
|
1195
|
+
if (attempt < maxPollRetries) {
|
|
1196
|
+
await sleep(pollIntervalMs);
|
|
1197
|
+
}
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
const stillUnconfirmed = [];
|
|
1201
|
+
for (const ctx of remaining) {
|
|
1202
|
+
const match = findChainOrderForSlot(bot, chainSnapshot, ctx.order.id, {
|
|
1203
|
+
sell: ctx.finalInts.sell,
|
|
1204
|
+
receive: ctx.finalInts.receive,
|
|
1205
|
+
orderType: ctx.order.type,
|
|
1206
|
+
fingerprint: createContexts.length > 0
|
|
1207
|
+
? buildCreateOpFingerprint({
|
|
1208
|
+
side: ctx.order.type,
|
|
1209
|
+
assetA: bot.manager?.assets?.assetA?.id,
|
|
1210
|
+
assetB: bot.manager?.assets?.assetB?.id,
|
|
1211
|
+
sellInt: ctx.finalInts.sell,
|
|
1212
|
+
receiveInt: ctx.finalInts.receive,
|
|
1213
|
+
slotId: ctx.order.id
|
|
1214
|
+
})
|
|
1215
|
+
: undefined
|
|
1216
|
+
});
|
|
1217
|
+
if (match) {
|
|
1218
|
+
bot.manager.logger.log(`[COW][POLL] Confirmed CREATE for slot ${ctx.order.id} on chain as ${match.id}`, 'debug');
|
|
1219
|
+
}
|
|
1220
|
+
else {
|
|
1221
|
+
stillUnconfirmed.push(ctx);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (stillUnconfirmed.length === 0) {
|
|
1225
|
+
const confirmed = createContexts;
|
|
1226
|
+
bot.manager.logger.log(`[COW][POLL] All ${confirmed.length} CREATE(s) confirmed on chain after ${attempt} poll(s)`, 'info');
|
|
1227
|
+
return { allConfirmed: true, confirmed, unconfirmed: [] };
|
|
1228
|
+
}
|
|
1229
|
+
remaining = stillUnconfirmed;
|
|
1230
|
+
if (attempt < maxPollRetries) {
|
|
1231
|
+
await sleep(pollIntervalMs);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
catch (pollErr) {
|
|
1235
|
+
bot.manager.logger.log(`[COW][POLL] Chain read attempt ${attempt}/${maxPollRetries} failed: ${getErrorMessage(pollErr)}`, 'warn');
|
|
1236
|
+
if (attempt < maxPollRetries) {
|
|
1237
|
+
await sleep(pollIntervalMs);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
const confirmed = createContexts.filter((ctx) => !remaining.includes(ctx));
|
|
1242
|
+
bot.manager.logger.log(`[COW][POLL] ${confirmed.length}/${createContexts.length} CREATE(s) confirmed after ${maxPollRetries} polls; ` +
|
|
1243
|
+
`${remaining.length} unconfirmed. Falling back to reconciliation.`, 'warn');
|
|
1244
|
+
return { allConfirmed: false, confirmed, unconfirmed: remaining };
|
|
1245
|
+
}
|
|
1110
1246
|
function restoreSkippedUpdateSlotsInWorkingGrid(bot, workingGrid, skippedSlotIds, skippedCount = 0) {
|
|
1111
1247
|
if (!workingGrid || !skippedSlotIds || skippedSlotIds.size === 0) {
|
|
1112
1248
|
return;
|
|
@@ -1578,6 +1714,12 @@ async function updateOrdersOnChainBatchCOW(bot, cowResult) {
|
|
|
1578
1714
|
}))
|
|
1579
1715
|
};
|
|
1580
1716
|
}
|
|
1717
|
+
// Pre-apply rotation state transitions to the working grid so the
|
|
1718
|
+
// COW commit is truly atomic for structural changes (source → VIRTUAL,
|
|
1719
|
+
// dest → ACTIVE with orderId). Remaining post-commit patches in
|
|
1720
|
+
// processBatchResults are limited to rawOnChain metadata enrichment
|
|
1721
|
+
// that depends on broadcast result data.
|
|
1722
|
+
applyRotationTransitionsToWorkingGrid(bot, workingGrid, executedContexts);
|
|
1581
1723
|
bot.manager.logger.log('[COW] Blockchain success - committing working grid to master', 'info');
|
|
1582
1724
|
await bot.manager._commitWorkingGrid(workingGrid, workingIndexes, workingBoundary, { skipRecalc: true });
|
|
1583
1725
|
const batchResult = await processBatchResults(bot, result, executedContexts);
|
|
@@ -1632,6 +1774,54 @@ async function updateOrdersOnChainBatchCOW(bot, cowResult) {
|
|
|
1632
1774
|
bot.manager.logger.log(`[COW] Non-atomic grouped execution detected (${err.groupsBroadcast}/${err.groupsTotal} groups broadcast). Local rollback cannot undo confirmed on-chain operations; next sync/reconcile will converge state.`, 'warn');
|
|
1633
1775
|
}
|
|
1634
1776
|
bot.manager.stopBroadcasting();
|
|
1777
|
+
// Chain polling: for uncertain broadcasts (not partial), try to confirm
|
|
1778
|
+
// CREATE operations on chain before clearing the working grid. If all
|
|
1779
|
+
// planned CREATEs are confirmed, the entire batch was accepted atomically
|
|
1780
|
+
// and we can commit the working grid directly, bypassing the expensive
|
|
1781
|
+
// reconciliation state machine. This handles the ~90% case where the
|
|
1782
|
+
// chain accepted the transaction but the response was lost.
|
|
1783
|
+
if (err instanceof BroadcastUncertainError && err.partialOnChainState !== true) {
|
|
1784
|
+
try {
|
|
1785
|
+
const confirmation = await pollChainForConfirmation(bot, opContexts);
|
|
1786
|
+
if (confirmation.allConfirmed) {
|
|
1787
|
+
// pollChainForConfirmation only verifies CREATE ops (see its doc).
|
|
1788
|
+
// If the batch had non-CREATE ops (UPDATEs/CANCELs), they are NOT
|
|
1789
|
+
// confirmed here — we assume atomic batch acceptance. Log the
|
|
1790
|
+
// composition so a misbehaving partial-broadcast (partialOnChainState
|
|
1791
|
+
// incorrectly false) leaves a forensic trace.
|
|
1792
|
+
const createCount = confirmation.confirmed.length;
|
|
1793
|
+
const totalOps = opContexts.length;
|
|
1794
|
+
if (createCount < totalOps) {
|
|
1795
|
+
bot.manager.logger.log(`[COW][UNCERTAIN] Chain polling confirmed ${createCount}/${totalOps} CREATEs on chain ` +
|
|
1796
|
+
`(${totalOps - createCount} non-CREATE ops assumed confirmed via atomic batch). ` +
|
|
1797
|
+
`Committing working grid.`, 'info');
|
|
1798
|
+
}
|
|
1799
|
+
else {
|
|
1800
|
+
bot.manager.logger.log(`[COW][UNCERTAIN] Chain polling confirmed all ${createCount} CREATE(s) on chain. Committing working grid directly.`, 'info');
|
|
1801
|
+
}
|
|
1802
|
+
applyRotationTransitionsToWorkingGrid(bot, workingGrid, opContexts);
|
|
1803
|
+
await bot.manager._commitWorkingGrid(workingGrid, workingIndexes, workingBoundary, { skipRecalc: true });
|
|
1804
|
+
// Enrich master grid with chain-assigned order IDs and amounts
|
|
1805
|
+
try {
|
|
1806
|
+
const accountRef = bot.accountId || bot.account?.id || bot.account;
|
|
1807
|
+
const freshChain = await chainOrders.readOpenOrders(accountRef);
|
|
1808
|
+
if (freshChain.length > 0 && typeof bot.manager.syncFromOpenOrders === 'function') {
|
|
1809
|
+
await bot.manager.syncFromOpenOrders(freshChain, { skipAccounting: true });
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
catch (syncErr) {
|
|
1813
|
+
bot.manager.logger.log(`[COW][UNCERTAIN] Chain sync after poll-confirmed commit failed: ${getErrorMessage(syncErr)}`, 'warn');
|
|
1814
|
+
}
|
|
1815
|
+
await bot.manager.persistGrid();
|
|
1816
|
+
bot.manager._clearWorkingGridRef();
|
|
1817
|
+
clearPendingBroadcasts(bot.manager?._pendingBroadcasts);
|
|
1818
|
+
return { executed: true, hadRotation: false, uncertainResolved: true };
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
catch (pollErr) {
|
|
1822
|
+
bot.manager.logger.log(`[COW][UNCERTAIN] Chain polling threw unexpectedly: ${getErrorMessage(pollErr)}. Falling back to reconciliation.`, 'error');
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1635
1825
|
bot.manager._clearWorkingGridRef();
|
|
1636
1826
|
if (err instanceof BroadcastUncertainError) {
|
|
1637
1827
|
return await reconcileAfterUncertainBroadcast(bot, err, opContexts);
|
|
@@ -1868,6 +2058,8 @@ module.exports = {
|
|
|
1868
2058
|
buildActionsFromPlan,
|
|
1869
2059
|
buildCowResultFromPlan,
|
|
1870
2060
|
restoreSkippedUpdateSlotsInWorkingGrid,
|
|
2061
|
+
applyRotationTransitionsToWorkingGrid,
|
|
2062
|
+
pollChainForConfirmation,
|
|
1871
2063
|
updateOrdersOnChainBatchCOW,
|
|
1872
2064
|
processBatchResults,
|
|
1873
2065
|
};
|