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.
@@ -72,29 +72,37 @@ class ConsolidateUtxos {
72
72
 
73
73
  async analyzeUtxos (options = {}) {
74
74
  try {
75
- const spendableUtxos = this.utxos.getSpendableXecUtxos()
75
+ const allUtxos = this.utxos.getSpendableXecUtxos()
76
76
 
77
- if (spendableUtxos.length < this.minUtxosForConsolidation) {
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 (${spendableUtxos.length} < ${this.minUtxosForConsolidation})`,
81
- totalUtxos: spendableUtxos.length,
82
- totalValue: this._calculateTotalValue(spendableUtxos)
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 = spendableUtxos
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: spendableUtxos.length,
96
- totalValue: this._calculateTotalValue(spendableUtxos),
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 utxos = this.utxos.getSpendableXecUtxos()
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: utxos.length
313
+ total: pureXecUtxos.length,
314
+ tokenUtxos: tokenUtxos.length,
315
+ tokenUtxosSkipped: tokenUtxos.length > 0
293
316
  }
294
317
 
295
- for (const utxo of utxos) {
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 utxos = this.utxos.getSpendableXecUtxos()
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 (utxos.length < 2) {
318
- return { savings: 0, reason: 'No optimization needed' }
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(utxos, this.defaultSatsPerByte)
322
- const optimalUtxoCount = Math.max(1, Math.ceil(utxos.length / 50)) // Optimal: ~50 UTXOs max
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: utxos.length,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minimal-xec-wallet",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A minimalist eCash (XEC) wallet npm library, for use in web apps. Supports eTokens.",
5
5
  "main": "./index.js",
6
6
  "module": "./dist/minimal-xec-wallet.min.js",