minimal-xec-wallet 1.0.2 → 1.0.3
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/lib/consolidate-utxos.js +55 -20
- package/package.json +1 -1
package/lib/consolidate-utxos.js
CHANGED
|
@@ -72,29 +72,37 @@ class ConsolidateUtxos {
|
|
|
72
72
|
|
|
73
73
|
async analyzeUtxos (options = {}) {
|
|
74
74
|
try {
|
|
75
|
-
const
|
|
75
|
+
const allUtxos = this.utxos.getSpendableXecUtxos()
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
// CRITICAL: Filter out token UTXOs to prevent token burning
|
|
78
|
+
const pureXecUtxos = allUtxos.filter(utxo => !utxo.token)
|
|
79
|
+
const tokenUtxos = allUtxos.filter(utxo => utxo.token)
|
|
80
|
+
|
|
81
|
+
if (pureXecUtxos.length < this.minUtxosForConsolidation) {
|
|
78
82
|
return {
|
|
79
83
|
shouldConsolidate: false,
|
|
80
|
-
reason: `Not enough UTXOs for consolidation (${
|
|
81
|
-
totalUtxos:
|
|
82
|
-
totalValue: this._calculateTotalValue(
|
|
84
|
+
reason: `Not enough pure XEC UTXOs for consolidation (${pureXecUtxos.length} < ${this.minUtxosForConsolidation})`,
|
|
85
|
+
totalUtxos: pureXecUtxos.length,
|
|
86
|
+
totalValue: this._calculateTotalValue(pureXecUtxos),
|
|
87
|
+
tokenUtxos: tokenUtxos.length,
|
|
88
|
+
tokenUtxosSkipped: tokenUtxos.length > 0
|
|
83
89
|
}
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
// Filter UTXOs that should be consolidated (smaller ones first)
|
|
87
|
-
const utxosToConsolidate =
|
|
93
|
+
const utxosToConsolidate = pureXecUtxos
|
|
88
94
|
.filter(utxo => utxo.value <= options.consolidationThreshold)
|
|
89
95
|
.sort((a, b) => a.value - b.value) // Sort by value ascending
|
|
90
96
|
|
|
91
97
|
if (utxosToConsolidate.length < this.minUtxosForConsolidation) {
|
|
92
98
|
return {
|
|
93
99
|
shouldConsolidate: false,
|
|
94
|
-
reason: `Not enough small UTXOs to consolidate (${utxosToConsolidate.length} below ${options.consolidationThreshold} satoshis)`,
|
|
95
|
-
totalUtxos:
|
|
96
|
-
totalValue: this._calculateTotalValue(
|
|
97
|
-
smallUtxos: utxosToConsolidate.length
|
|
100
|
+
reason: `Not enough small pure XEC UTXOs to consolidate (${utxosToConsolidate.length} below ${options.consolidationThreshold} satoshis)`,
|
|
101
|
+
totalUtxos: pureXecUtxos.length,
|
|
102
|
+
totalValue: this._calculateTotalValue(pureXecUtxos),
|
|
103
|
+
smallUtxos: utxosToConsolidate.length,
|
|
104
|
+
tokenUtxos: tokenUtxos.length,
|
|
105
|
+
tokenUtxosSkipped: tokenUtxos.length > 0
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
|
|
@@ -117,6 +125,8 @@ class ConsolidateUtxos {
|
|
|
117
125
|
totalValue: this._calculateTotalValue(utxosToConsolidate),
|
|
118
126
|
consolidationFee,
|
|
119
127
|
potentialSavings: totalSavings,
|
|
128
|
+
tokenUtxos: tokenUtxos.length,
|
|
129
|
+
tokenUtxosSkipped: tokenUtxos.length > 0,
|
|
120
130
|
consolidationPlans
|
|
121
131
|
}
|
|
122
132
|
} catch (err) {
|
|
@@ -167,6 +177,12 @@ class ConsolidateUtxos {
|
|
|
167
177
|
|
|
168
178
|
for (const plan of consolidationPlans) {
|
|
169
179
|
try {
|
|
180
|
+
// CRITICAL SAFETY CHECK: Ensure no token UTXOs are being consolidated
|
|
181
|
+
const tokenUtxosInPlan = plan.inputUtxos.filter(utxo => utxo.token)
|
|
182
|
+
if (tokenUtxosInPlan.length > 0) {
|
|
183
|
+
throw new Error(`SAFETY ABORT: Plan contains ${tokenUtxosInPlan.length} token UTXOs. Consolidation would burn tokens!`)
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
// Create consolidation transaction - send all value to same address
|
|
171
187
|
const outputs = [{
|
|
172
188
|
address: this.wallet.walletInfo.xecAddress,
|
|
@@ -283,16 +299,24 @@ class ConsolidateUtxos {
|
|
|
283
299
|
|
|
284
300
|
getUtxoDistribution () {
|
|
285
301
|
try {
|
|
286
|
-
const
|
|
302
|
+
const allUtxos = this.utxos.getSpendableXecUtxos()
|
|
303
|
+
|
|
304
|
+
// Separate pure XEC from token UTXOs
|
|
305
|
+
const pureXecUtxos = allUtxos.filter(utxo => !utxo.token)
|
|
306
|
+
const tokenUtxos = allUtxos.filter(utxo => utxo.token)
|
|
307
|
+
|
|
287
308
|
const distribution = {
|
|
288
309
|
dust: 0, // < 1000 sats
|
|
289
310
|
small: 0, // 1000 - 10000 sats
|
|
290
311
|
medium: 0, // 10000 - 100000 sats
|
|
291
312
|
large: 0, // > 100000 sats
|
|
292
|
-
total:
|
|
313
|
+
total: pureXecUtxos.length,
|
|
314
|
+
tokenUtxos: tokenUtxos.length,
|
|
315
|
+
tokenUtxosSkipped: tokenUtxos.length > 0
|
|
293
316
|
}
|
|
294
317
|
|
|
295
|
-
|
|
318
|
+
// Only analyze pure XEC UTXOs for consolidation
|
|
319
|
+
for (const utxo of pureXecUtxos) {
|
|
296
320
|
if (utxo.value < 1000) {
|
|
297
321
|
distribution.dust++
|
|
298
322
|
} else if (utxo.value < 10000) {
|
|
@@ -312,22 +336,33 @@ class ConsolidateUtxos {
|
|
|
312
336
|
|
|
313
337
|
estimateOptimizationSavings () {
|
|
314
338
|
try {
|
|
315
|
-
const
|
|
339
|
+
const allUtxos = this.utxos.getSpendableXecUtxos()
|
|
340
|
+
|
|
341
|
+
// Only analyze pure XEC UTXOs (tokens are preserved separately)
|
|
342
|
+
const pureXecUtxos = allUtxos.filter(utxo => !utxo.token)
|
|
343
|
+
const tokenUtxos = allUtxos.filter(utxo => utxo.token)
|
|
316
344
|
|
|
317
|
-
if (
|
|
318
|
-
return {
|
|
345
|
+
if (pureXecUtxos.length < 2) {
|
|
346
|
+
return {
|
|
347
|
+
savings: 0,
|
|
348
|
+
reason: 'No optimization needed for pure XEC UTXOs',
|
|
349
|
+
currentUtxos: pureXecUtxos.length,
|
|
350
|
+
tokenUtxos: tokenUtxos.length
|
|
351
|
+
}
|
|
319
352
|
}
|
|
320
353
|
|
|
321
|
-
const currentFee = this._estimateCurrentSpendingFee(
|
|
322
|
-
const optimalUtxoCount = Math.max(1, Math.ceil(
|
|
354
|
+
const currentFee = this._estimateCurrentSpendingFee(pureXecUtxos, this.defaultSatsPerByte)
|
|
355
|
+
const optimalUtxoCount = Math.max(1, Math.ceil(pureXecUtxos.length / 50)) // Optimal: ~50 UTXOs max
|
|
323
356
|
const optimizedFee = this._estimateFutureSpendingFee(optimalUtxoCount, this.defaultSatsPerByte)
|
|
324
357
|
|
|
325
358
|
return {
|
|
326
359
|
savings: currentFee - optimizedFee,
|
|
327
|
-
currentUtxos:
|
|
360
|
+
currentUtxos: pureXecUtxos.length,
|
|
328
361
|
optimalUtxos: optimalUtxoCount,
|
|
329
362
|
currentEstimatedFee: currentFee,
|
|
330
|
-
optimizedEstimatedFee: optimizedFee
|
|
363
|
+
optimizedEstimatedFee: optimizedFee,
|
|
364
|
+
tokenUtxos: tokenUtxos.length,
|
|
365
|
+
tokenUtxosPreserved: tokenUtxos.length
|
|
331
366
|
}
|
|
332
367
|
} catch (err) {
|
|
333
368
|
throw new Error(`Optimization savings estimation failed: ${err.message}`)
|
package/package.json
CHANGED