minimal-xec-wallet 1.0.1
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/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/minimal-xec-wallet.js +66268 -0
- package/dist/minimal-xec-wallet.min.js +55 -0
- package/examples/README.md +380 -0
- package/examples/advanced/browser-compatibility-test.js +263 -0
- package/examples/advanced/get-xec-price.js +149 -0
- package/examples/advanced/optimize-utxos.js +255 -0
- package/examples/advanced/send-op-return.js +216 -0
- package/examples/browser-test.html +350 -0
- package/examples/key-management/derive-addresses.js +191 -0
- package/examples/key-management/export-to-wif.js +114 -0
- package/examples/key-management/validate-address.js +214 -0
- package/examples/optimization/simple-consolidation-test.js +79 -0
- package/examples/optimization/test-utxo-consolidation.js +179 -0
- package/examples/test-examples.js +1204 -0
- package/examples/tokens/burn-tokens.js +293 -0
- package/examples/tokens/get-token-balance.js +169 -0
- package/examples/tokens/get-token-info.js +269 -0
- package/examples/tokens/list-all-tokens.js +162 -0
- package/examples/tokens/send-any-token.js +260 -0
- package/examples/tokens/test-main-wallet-integration.js +193 -0
- package/examples/transactions/send-all-xec.js +205 -0
- package/examples/transactions/send-to-multiple.js +217 -0
- package/examples/transactions/send-xec.js +191 -0
- package/examples/utils/show-qr.js +119 -0
- package/examples/utils/wallet-helper.js +176 -0
- package/examples/validation/comprehensive-infrastructure-test.js +210 -0
- package/examples/wallet-creation/create-new-wallet.js +67 -0
- package/examples/wallet-creation/import-from-wif.js +135 -0
- package/examples/wallet-creation/restore-from-mnemonic.js +100 -0
- package/examples/wallet-info/get-balance.js +99 -0
- package/examples/wallet-info/get-transactions.js +157 -0
- package/examples/wallet-info/get-utxos.js +145 -0
- package/examples/wallet.json +11 -0
- package/lib/adapters/robust-chronik-router.js +507 -0
- package/lib/adapters/router.js +651 -0
- package/lib/alp-token-handler.js +581 -0
- package/lib/browser-wasm-loader.js +271 -0
- package/lib/consolidate-utxos.js +338 -0
- package/lib/hybrid-token-manager.js +322 -0
- package/lib/key-derivation.js +466 -0
- package/lib/op-return.js +314 -0
- package/lib/security.js +270 -0
- package/lib/send-xec.js +396 -0
- package/lib/slp-token-handler.js +572 -0
- package/lib/token-protocol-detector.js +307 -0
- package/lib/utxos.js +303 -0
- package/package.json +125 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Get the current XEC to USD exchange rate.
|
|
3
|
+
This example shows how to fetch pricing information for XEC.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const MinimalXECWallet = require('../../index')
|
|
7
|
+
const WalletHelper = require('../utils/wallet-helper')
|
|
8
|
+
|
|
9
|
+
async function getXecPrice () {
|
|
10
|
+
try {
|
|
11
|
+
console.log('š± Getting XEC price information...\n')
|
|
12
|
+
|
|
13
|
+
// Load wallet from file (optional - just for consistency)
|
|
14
|
+
const walletData = WalletHelper.loadWallet()
|
|
15
|
+
|
|
16
|
+
// Create wallet instance (we don't need wallet data for price queries)
|
|
17
|
+
const wallet = new MinimalXECWallet()
|
|
18
|
+
await wallet.walletInfoPromise
|
|
19
|
+
|
|
20
|
+
console.log('š Fetching XEC price from exchange APIs...')
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Get XEC/USD price
|
|
24
|
+
const xecUsdPrice = await wallet.getXecUsd()
|
|
25
|
+
|
|
26
|
+
console.log('\nš° XEC Price Information:')
|
|
27
|
+
console.log('ā'.repeat(50))
|
|
28
|
+
console.log(`XEC/USD: $${xecUsdPrice.toFixed(8)}`)
|
|
29
|
+
console.log(`1 USD: ${(1 / xecUsdPrice).toLocaleString()} XEC`)
|
|
30
|
+
console.log('ā'.repeat(50))
|
|
31
|
+
|
|
32
|
+
// Calculate various amounts in USD
|
|
33
|
+
const commonAmounts = [100, 1000, 10000, 100000, 1000000]
|
|
34
|
+
|
|
35
|
+
console.log('\nš XEC to USD Conversion Table:')
|
|
36
|
+
console.log('ā'.repeat(50))
|
|
37
|
+
console.log('XEC Amount USD Value')
|
|
38
|
+
console.log('ā'.repeat(50))
|
|
39
|
+
|
|
40
|
+
commonAmounts.forEach(xecAmount => {
|
|
41
|
+
const usdValue = xecAmount * xecUsdPrice
|
|
42
|
+
const xecFormatted = xecAmount.toLocaleString().padEnd(15)
|
|
43
|
+
const usdFormatted = `$${usdValue.toFixed(6)}`
|
|
44
|
+
console.log(`${xecFormatted} ${usdFormatted}`)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// Show wallet value if wallet exists
|
|
48
|
+
if (walletData) {
|
|
49
|
+
console.log('\nš¦ Your Wallet Value:')
|
|
50
|
+
console.log('ā'.repeat(50))
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const walletForPrice = new MinimalXECWallet(walletData.mnemonic || walletData.privateKey)
|
|
54
|
+
await walletForPrice.walletInfoPromise
|
|
55
|
+
|
|
56
|
+
const balance = await walletForPrice.getXecBalance()
|
|
57
|
+
const walletUsdValue = balance * xecUsdPrice
|
|
58
|
+
|
|
59
|
+
console.log(`XEC Balance: ${balance.toLocaleString()} XEC`)
|
|
60
|
+
console.log(`USD Value: $${walletUsdValue.toFixed(6)} USD`)
|
|
61
|
+
|
|
62
|
+
if (walletUsdValue > 0) {
|
|
63
|
+
console.log('\nš” Value Breakdown:')
|
|
64
|
+
console.log(`⢠Your ${balance.toLocaleString()} XEC is worth $${walletUsdValue.toFixed(6)}`)
|
|
65
|
+
console.log(`⢠At current rate of $${xecUsdPrice.toFixed(8)} per XEC`)
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.log('(Unable to fetch wallet balance for price calculation)')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Market insights
|
|
73
|
+
console.log('\nš Market Insights:')
|
|
74
|
+
console.log('ā'.repeat(50))
|
|
75
|
+
|
|
76
|
+
// Calculate market cap implications (approximate)
|
|
77
|
+
const totalSupply = 21000000000000 // 21 trillion XEC (approximate)
|
|
78
|
+
const marketCap = totalSupply * xecUsdPrice
|
|
79
|
+
|
|
80
|
+
console.log(`Estimated Market Cap: $${(marketCap / 1000000).toFixed(2)}M USD`)
|
|
81
|
+
console.log(`Price per Million XEC: $${(xecUsdPrice * 1000000).toFixed(2)}`)
|
|
82
|
+
console.log(`Price per Billion XEC: $${(xecUsdPrice * 1000000000).toFixed(2)}`)
|
|
83
|
+
|
|
84
|
+
// Historical context note
|
|
85
|
+
console.log('\nš Price Notes:')
|
|
86
|
+
console.log('⢠XEC prices are highly volatile')
|
|
87
|
+
console.log('⢠This is real-time data from available APIs')
|
|
88
|
+
console.log('⢠Prices may vary between exchanges')
|
|
89
|
+
console.log('⢠Use for informational purposes only')
|
|
90
|
+
console.log('⢠Not financial advice')
|
|
91
|
+
|
|
92
|
+
// Exchange information
|
|
93
|
+
console.log('\nšŖ Where to Trade XEC:')
|
|
94
|
+
console.log('⢠Binance (XEC/USDT, XEC/BTC)')
|
|
95
|
+
console.log('⢠KuCoin (XEC/USDT)')
|
|
96
|
+
console.log('⢠Gate.io (XEC/USDT)')
|
|
97
|
+
console.log('⢠OKX (XEC/USDT)')
|
|
98
|
+
console.log('⢠Bitfinex (XEC/USD)')
|
|
99
|
+
console.log('⢠Check CoinGecko/CoinMarketCap for full list')
|
|
100
|
+
} catch (priceErr) {
|
|
101
|
+
console.log('\nā Price API Error:', priceErr.message)
|
|
102
|
+
console.log('\nš” Price API Issues:')
|
|
103
|
+
console.log(' ⢠Price APIs may be temporarily unavailable')
|
|
104
|
+
console.log(' ⢠Network connectivity issues')
|
|
105
|
+
console.log(' ⢠API rate limiting')
|
|
106
|
+
console.log('')
|
|
107
|
+
console.log(' Alternative price sources:')
|
|
108
|
+
console.log(' ⢠CoinGecko: https://coingecko.com/en/coins/ecash')
|
|
109
|
+
console.log(' ⢠CoinMarketCap: https://coinmarketcap.com/currencies/ecash/')
|
|
110
|
+
console.log(' ⢠Exchange websites directly')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Additional resources
|
|
114
|
+
console.log('\nš Useful Resources:')
|
|
115
|
+
console.log('⢠eCash Website: https://e.cash')
|
|
116
|
+
console.log('⢠Price Charts: https://coinmarketcap.com/currencies/ecash/')
|
|
117
|
+
console.log('⢠Market Data: https://coingecko.com/en/coins/ecash')
|
|
118
|
+
console.log('⢠Exchange List: https://coinmarketcap.com/currencies/ecash/markets/')
|
|
119
|
+
|
|
120
|
+
console.log('\nš± Mobile Apps:')
|
|
121
|
+
console.log('⢠CoinMarketCap app')
|
|
122
|
+
console.log('⢠CoinGecko app')
|
|
123
|
+
console.log('⢠Exchange apps (Binance, KuCoin, etc.)')
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.error('ā Failed to get XEC price:', err.message)
|
|
126
|
+
|
|
127
|
+
// Provide helpful error context
|
|
128
|
+
if (err.message.includes('network') || err.message.includes('connection')) {
|
|
129
|
+
console.log('\nš Network Error:')
|
|
130
|
+
console.log(' ⢠Check your internet connection')
|
|
131
|
+
console.log(' ⢠Price APIs might be temporarily unavailable')
|
|
132
|
+
console.log(' ⢠Try again in a few moments')
|
|
133
|
+
console.log('')
|
|
134
|
+
console.log(' Manual price check:')
|
|
135
|
+
console.log(' ⢠Visit https://coinmarketcap.com/currencies/ecash/')
|
|
136
|
+
console.log(' ⢠Or https://coingecko.com/en/coins/ecash')
|
|
137
|
+
} else if (err.message.includes('api') || err.message.includes('rate')) {
|
|
138
|
+
console.log('\nš« API Error:')
|
|
139
|
+
console.log(' ⢠Price API might be rate-limited')
|
|
140
|
+
console.log(' ⢠API service might be down')
|
|
141
|
+
console.log(' ⢠Try alternative price sources')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
process.exit(1)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Run the example
|
|
149
|
+
getXecPrice()
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Optimize wallet UTXOs by consolidating them.
|
|
3
|
+
This example shows how to reduce the number of UTXOs to lower future transaction fees.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const MinimalXECWallet = require('../../index')
|
|
7
|
+
const WalletHelper = require('../utils/wallet-helper')
|
|
8
|
+
|
|
9
|
+
// Get command line arguments
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
const dryRun = args.includes('--dry-run') || args.includes('-n')
|
|
12
|
+
|
|
13
|
+
function showUsage () {
|
|
14
|
+
console.log('Usage: node optimize-utxos.js [--dry-run]')
|
|
15
|
+
console.log('')
|
|
16
|
+
console.log('Options:')
|
|
17
|
+
console.log(' --dry-run, -n Show optimization plan without executing')
|
|
18
|
+
console.log('')
|
|
19
|
+
console.log('Examples:')
|
|
20
|
+
console.log(' node optimize-utxos.js --dry-run # Preview optimization')
|
|
21
|
+
console.log(' node optimize-utxos.js # Execute optimization')
|
|
22
|
+
console.log('')
|
|
23
|
+
console.log('Purpose:')
|
|
24
|
+
console.log(' ⢠Consolidates multiple small UTXOs into fewer larger ones')
|
|
25
|
+
console.log(' ⢠Reduces future transaction fees')
|
|
26
|
+
console.log(' ⢠Improves wallet performance')
|
|
27
|
+
console.log(' ⢠Cleans up "dust" outputs')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function analyzeUtxos (wallet) {
|
|
31
|
+
console.log('š Analyzing wallet UTXOs...')
|
|
32
|
+
|
|
33
|
+
const utxoData = await wallet.getUtxos()
|
|
34
|
+
const utxos = utxoData.utxos || []
|
|
35
|
+
const spendableUtxos = utxos.filter(utxo => utxo.blockHeight !== -1)
|
|
36
|
+
|
|
37
|
+
if (spendableUtxos.length === 0) {
|
|
38
|
+
console.log('\nšø No spendable UTXOs found!')
|
|
39
|
+
console.log(' Your wallet has no confirmed UTXOs to optimize.')
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Calculate statistics
|
|
44
|
+
const totalValue = spendableUtxos.reduce((sum, utxo) => sum + utxo.value, 0)
|
|
45
|
+
const averageValue = totalValue / spendableUtxos.length
|
|
46
|
+
const values = spendableUtxos.map(utxo => utxo.value).sort((a, b) => a - b)
|
|
47
|
+
const medianValue = values[Math.floor(values.length / 2)]
|
|
48
|
+
|
|
49
|
+
// Categorize UTXOs
|
|
50
|
+
const dustUtxos = spendableUtxos.filter(utxo => utxo.value < 546) // < 5.46 XEC
|
|
51
|
+
const smallUtxos = spendableUtxos.filter(utxo => utxo.value >= 546 && utxo.value < 10000) // 5.46 - 100 XEC
|
|
52
|
+
const mediumUtxos = spendableUtxos.filter(utxo => utxo.value >= 10000 && utxo.value < 100000) // 100 - 1000 XEC
|
|
53
|
+
const largeUtxos = spendableUtxos.filter(utxo => utxo.value >= 100000) // > 1000 XEC
|
|
54
|
+
|
|
55
|
+
console.log('\nš UTXO Analysis:')
|
|
56
|
+
console.log('ā'.repeat(60))
|
|
57
|
+
console.log(`Total UTXOs: ${spendableUtxos.length}`)
|
|
58
|
+
console.log(`Total Value: ${(totalValue / 100).toLocaleString()} XEC`)
|
|
59
|
+
console.log(`Average Size: ${(averageValue / 100).toLocaleString()} XEC`)
|
|
60
|
+
console.log(`Median Size: ${(medianValue / 100).toLocaleString()} XEC`)
|
|
61
|
+
console.log('ā'.repeat(60))
|
|
62
|
+
|
|
63
|
+
console.log('\nš·ļø UTXO Categories:')
|
|
64
|
+
console.log(`Dust (< 5.46 XEC): ${dustUtxos.length} UTXOs`)
|
|
65
|
+
console.log(`Small (5.46 - 100 XEC): ${smallUtxos.length} UTXOs`)
|
|
66
|
+
console.log(`Medium (100 - 1000 XEC): ${mediumUtxos.length} UTXOs`)
|
|
67
|
+
console.log(`Large (> 1000 XEC): ${largeUtxos.length} UTXOs`)
|
|
68
|
+
|
|
69
|
+
// Calculate potential fee savings
|
|
70
|
+
const currentTxCost = spendableUtxos.length * 150 * 1.2 / 100 // 150 bytes per input * 1.2 sat/byte
|
|
71
|
+
const optimizedTxCost = Math.min(spendableUtxos.length, 5) * 150 * 1.2 / 100 // Assume max 5 UTXOs after optimization
|
|
72
|
+
const potentialSavings = currentTxCost - optimizedTxCost
|
|
73
|
+
|
|
74
|
+
console.log('\nš° Fee Impact Analysis:')
|
|
75
|
+
console.log(`Current TX cost estimate: ${currentTxCost.toFixed(4)} XEC`)
|
|
76
|
+
console.log(`Optimized TX cost estimate: ${optimizedTxCost.toFixed(4)} XEC`)
|
|
77
|
+
console.log(`Potential savings per TX: ${potentialSavings.toFixed(4)} XEC`)
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
total: spendableUtxos.length,
|
|
81
|
+
dust: dustUtxos.length,
|
|
82
|
+
small: smallUtxos.length,
|
|
83
|
+
medium: mediumUtxos.length,
|
|
84
|
+
large: largeUtxos.length,
|
|
85
|
+
totalValue,
|
|
86
|
+
needsOptimization: spendableUtxos.length > 10 || dustUtxos.length > 0
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function optimizeUtxos () {
|
|
91
|
+
try {
|
|
92
|
+
console.log('ā” UTXO Optimization Tool\n')
|
|
93
|
+
|
|
94
|
+
if (dryRun) {
|
|
95
|
+
console.log('š DRY RUN MODE - No transactions will be sent\n')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Load wallet from file
|
|
99
|
+
const walletData = WalletHelper.loadWallet()
|
|
100
|
+
if (!walletData) {
|
|
101
|
+
console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Create wallet instance from saved data
|
|
106
|
+
const wallet = new MinimalXECWallet(walletData.mnemonic || walletData.privateKey)
|
|
107
|
+
await wallet.walletInfoPromise
|
|
108
|
+
|
|
109
|
+
// Initialize wallet
|
|
110
|
+
await wallet.initialize()
|
|
111
|
+
|
|
112
|
+
console.log('š° Checking wallet balance...')
|
|
113
|
+
const balance = await wallet.getXecBalance()
|
|
114
|
+
|
|
115
|
+
console.log('\nš Wallet Information:')
|
|
116
|
+
console.log('ā'.repeat(60))
|
|
117
|
+
console.log(`Address: ${walletData.xecAddress}`)
|
|
118
|
+
console.log(`Balance: ${balance.toLocaleString()} XEC`)
|
|
119
|
+
console.log('ā'.repeat(60))
|
|
120
|
+
|
|
121
|
+
// Analyze current UTXO state
|
|
122
|
+
const analysis = await analyzeUtxos(wallet)
|
|
123
|
+
if (!analysis) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check if optimization is needed
|
|
128
|
+
if (!analysis.needsOptimization) {
|
|
129
|
+
console.log('\nā
Your wallet is already optimized!')
|
|
130
|
+
console.log(' ⢠You have a reasonable number of UTXOs')
|
|
131
|
+
console.log(' ⢠No dust UTXOs detected')
|
|
132
|
+
console.log(' ⢠Transaction fees should be minimal')
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log('\nš” Optimization Recommendations:')
|
|
137
|
+
|
|
138
|
+
if (analysis.dust > 0) {
|
|
139
|
+
console.log(` ⢠Consolidate ${analysis.dust} dust UTXOs (< 5.46 XEC)`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (analysis.total > 20) {
|
|
143
|
+
console.log(` ⢠Reduce UTXO count from ${analysis.total} to ~5-10`)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (analysis.small > 10) {
|
|
147
|
+
console.log(` ⢠Combine ${analysis.small} small UTXOs`)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// In dry run mode, just show the plan
|
|
151
|
+
if (dryRun) {
|
|
152
|
+
console.log('\nš DRY RUN COMPLETE')
|
|
153
|
+
console.log(' Run without --dry-run to execute optimization')
|
|
154
|
+
console.log(' Estimated optimization fee: ~0.01-0.05 XEC')
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Confirm optimization
|
|
159
|
+
console.log('\nā ļø UTXO Optimization Confirmation')
|
|
160
|
+
console.log(' This will consolidate your UTXOs to improve efficiency.')
|
|
161
|
+
console.log(' Benefits:')
|
|
162
|
+
console.log(' ⢠Lower future transaction fees')
|
|
163
|
+
console.log(' ⢠Faster transaction creation')
|
|
164
|
+
console.log(' ⢠Cleaner wallet state')
|
|
165
|
+
console.log('')
|
|
166
|
+
console.log(' Cost:')
|
|
167
|
+
console.log(' ⢠One-time consolidation fee (~0.01-0.05 XEC)')
|
|
168
|
+
console.log(' ⢠UTXOs will be temporarily locked during confirmation')
|
|
169
|
+
|
|
170
|
+
const readline = require('readline')
|
|
171
|
+
const rl = readline.createInterface({
|
|
172
|
+
input: process.stdin,
|
|
173
|
+
output: process.stdout
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
const confirmed = await new Promise((resolve) => {
|
|
177
|
+
rl.question('\nDo you want to optimize your UTXOs? (yes/no): ', (answer) => {
|
|
178
|
+
rl.close()
|
|
179
|
+
resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
if (!confirmed) {
|
|
184
|
+
console.log('ā UTXO optimization cancelled by user')
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log('\nš Starting UTXO optimization...')
|
|
189
|
+
|
|
190
|
+
// Run the optimization
|
|
191
|
+
const result = await wallet.optimize(false) // false = not dry run
|
|
192
|
+
|
|
193
|
+
if (result && result.txid) {
|
|
194
|
+
console.log('\nā
UTXO optimization completed successfully!')
|
|
195
|
+
console.log('ā'.repeat(60))
|
|
196
|
+
console.log(`Transaction ID: ${result.txid}`)
|
|
197
|
+
console.log(`UTXOs consolidated: ${result.utxosConsolidated || 'Multiple'}`)
|
|
198
|
+
console.log(`Fee paid: ${result.fee ? (result.fee / 100).toLocaleString() + ' XEC' : 'Calculated automatically'}`)
|
|
199
|
+
console.log('ā'.repeat(60))
|
|
200
|
+
|
|
201
|
+
// Show updated state
|
|
202
|
+
console.log('\nš° Getting updated balance...')
|
|
203
|
+
await new Promise(resolve => setTimeout(resolve, 2000)) // Wait 2 seconds
|
|
204
|
+
|
|
205
|
+
const newBalance = await wallet.getXecBalance()
|
|
206
|
+
console.log(`New Balance: ${newBalance.toLocaleString()} XEC`)
|
|
207
|
+
|
|
208
|
+
console.log('\nš View Transaction:')
|
|
209
|
+
console.log(` Explorer: https://explorer.e.cash/tx/${result.txid}`)
|
|
210
|
+
|
|
211
|
+
console.log('\nš What happened:')
|
|
212
|
+
console.log(' ⢠Multiple small UTXOs were combined into fewer larger ones')
|
|
213
|
+
console.log(' ⢠Future transactions will require lower fees')
|
|
214
|
+
console.log(' ⢠Your wallet is now more efficient')
|
|
215
|
+
console.log(' ⢠Wait for confirmation before making new transactions')
|
|
216
|
+
|
|
217
|
+
console.log('\nā±ļø Next Steps:')
|
|
218
|
+
console.log(' ⢠Wait 1-10 minutes for transaction confirmation')
|
|
219
|
+
console.log(' ⢠Check new UTXO state: node examples/wallet-info/get-utxos.js')
|
|
220
|
+
console.log(' ⢠Your wallet is now optimized for efficient transactions')
|
|
221
|
+
} else {
|
|
222
|
+
console.log('\nā UTXO optimization failed or was not needed')
|
|
223
|
+
console.log(' Possible reasons:')
|
|
224
|
+
console.log(' ⢠UTXOs are already optimal')
|
|
225
|
+
console.log(' ⢠Insufficient balance for optimization fee')
|
|
226
|
+
console.log(' ⢠Network error during optimization')
|
|
227
|
+
}
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.error('ā Failed to optimize UTXOs:', err.message)
|
|
230
|
+
|
|
231
|
+
// Provide helpful error context
|
|
232
|
+
if (err.message.includes('insufficient')) {
|
|
233
|
+
console.log('\nšø Insufficient Funds:')
|
|
234
|
+
console.log(' ⢠Your wallet needs enough XEC to pay consolidation fees')
|
|
235
|
+
console.log(' ⢠Try optimizing when you have a larger balance')
|
|
236
|
+
console.log(' ⢠Each consolidation transaction requires a small fee')
|
|
237
|
+
} else if (err.message.includes('network')) {
|
|
238
|
+
console.log('\nš Network Error:')
|
|
239
|
+
console.log(' ⢠Check your internet connection')
|
|
240
|
+
console.log(' ⢠The network might be temporarily unavailable')
|
|
241
|
+
console.log(' ⢠Try again in a few moments')
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
process.exit(1)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Show usage if requested
|
|
249
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
250
|
+
showUsage()
|
|
251
|
+
process.exit(0)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Run the example
|
|
255
|
+
optimizeUtxos()
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Send an OP_RETURN transaction with custom data.
|
|
3
|
+
This example shows how to embed data on the XEC blockchain.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const MinimalXECWallet = require('../../index')
|
|
7
|
+
const WalletHelper = require('../utils/wallet-helper')
|
|
8
|
+
|
|
9
|
+
// Get command line arguments
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
|
|
12
|
+
function showUsage () {
|
|
13
|
+
console.log('Usage: node send-op-return.js <message> [xec_amount]')
|
|
14
|
+
console.log('')
|
|
15
|
+
console.log('Examples:')
|
|
16
|
+
console.log(' node send-op-return.js "Hello XEC blockchain!"')
|
|
17
|
+
console.log(' node send-op-return.js "Document hash: abc123..." 5.46')
|
|
18
|
+
console.log(' node send-op-return.js "Timestamp: 2024-01-01" 0')
|
|
19
|
+
console.log('')
|
|
20
|
+
console.log('Parameters:')
|
|
21
|
+
console.log(' message: Text to embed in the blockchain (max 220 bytes)')
|
|
22
|
+
console.log(' xec_amount: Optional XEC to send to yourself (default: 0)')
|
|
23
|
+
console.log('')
|
|
24
|
+
console.log('Note: OP_RETURN data is permanent and publicly visible!')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function sendOpReturn () {
|
|
28
|
+
try {
|
|
29
|
+
console.log('š Sending OP_RETURN transaction...\n')
|
|
30
|
+
|
|
31
|
+
// Check arguments
|
|
32
|
+
if (args.length < 1) {
|
|
33
|
+
console.log('ā No message provided')
|
|
34
|
+
showUsage()
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const message = args[0]
|
|
39
|
+
const xecAmount = args.length > 1 ? parseFloat(args[1]) : 0
|
|
40
|
+
|
|
41
|
+
// Validate message
|
|
42
|
+
if (!message || message.length === 0) {
|
|
43
|
+
console.log('ā Message cannot be empty')
|
|
44
|
+
showUsage()
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (message.length > 220) {
|
|
49
|
+
console.log('ā Message too long. Maximum 220 characters allowed.')
|
|
50
|
+
console.log(` Your message: ${message.length} characters`)
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Validate amount
|
|
55
|
+
if (isNaN(xecAmount) || xecAmount < 0) {
|
|
56
|
+
console.log('ā Invalid XEC amount. Must be 0 or positive number')
|
|
57
|
+
showUsage()
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Load wallet from file
|
|
62
|
+
const walletData = WalletHelper.loadWallet()
|
|
63
|
+
if (!walletData) {
|
|
64
|
+
console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Create wallet instance from saved data
|
|
69
|
+
const wallet = new MinimalXECWallet(walletData.mnemonic || walletData.privateKey)
|
|
70
|
+
await wallet.walletInfoPromise
|
|
71
|
+
|
|
72
|
+
// Initialize wallet
|
|
73
|
+
await wallet.initialize()
|
|
74
|
+
|
|
75
|
+
console.log('š° Checking wallet balance...')
|
|
76
|
+
const balance = await wallet.getXecBalance()
|
|
77
|
+
|
|
78
|
+
console.log('\nš OP_RETURN Transaction Details:')
|
|
79
|
+
console.log('ā'.repeat(60))
|
|
80
|
+
console.log(`From: ${walletData.xecAddress}`)
|
|
81
|
+
console.log(`Message: "${message}"`)
|
|
82
|
+
console.log(`Message Length: ${message.length} bytes`)
|
|
83
|
+
console.log(`XEC Amount: ${xecAmount.toLocaleString()} XEC`)
|
|
84
|
+
console.log(`Current Balance: ${balance.toLocaleString()} XEC`)
|
|
85
|
+
console.log('ā'.repeat(60))
|
|
86
|
+
|
|
87
|
+
// Check balance
|
|
88
|
+
const estimatedFee = 0.01 // Rough estimate
|
|
89
|
+
const totalCost = xecAmount + estimatedFee
|
|
90
|
+
|
|
91
|
+
if (balance < totalCost) {
|
|
92
|
+
console.log('\nā Insufficient balance!')
|
|
93
|
+
console.log(` Required: ~${totalCost.toLocaleString()} XEC (including estimated fee)`)
|
|
94
|
+
console.log(` Available: ${balance.toLocaleString()} XEC`)
|
|
95
|
+
console.log(' Fund your wallet or reduce the XEC amount')
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Show what OP_RETURN means
|
|
100
|
+
console.log('\nš About OP_RETURN:')
|
|
101
|
+
console.log(' ⢠OP_RETURN allows embedding data in blockchain transactions')
|
|
102
|
+
console.log(' ⢠Data is permanent and publicly visible')
|
|
103
|
+
console.log(' ⢠Useful for timestamps, document hashes, certificates')
|
|
104
|
+
console.log(' ⢠Data cannot be spent (provably unspendable)')
|
|
105
|
+
|
|
106
|
+
// Encode message to hex
|
|
107
|
+
const messageHex = Buffer.from(message, 'utf8').toString('hex')
|
|
108
|
+
console.log(`\nš Encoded Message: ${messageHex}`)
|
|
109
|
+
|
|
110
|
+
// Confirm transaction
|
|
111
|
+
console.log('\nā ļø OP_RETURN Transaction Confirmation')
|
|
112
|
+
console.log(' This data will be permanently stored on the blockchain!')
|
|
113
|
+
console.log(' Make sure you want to make this information public.')
|
|
114
|
+
|
|
115
|
+
const readline = require('readline')
|
|
116
|
+
const rl = readline.createInterface({
|
|
117
|
+
input: process.stdin,
|
|
118
|
+
output: process.stdout
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const confirmed = await new Promise((resolve) => {
|
|
122
|
+
rl.question('\nDo you want to proceed? (yes/no): ', (answer) => {
|
|
123
|
+
rl.close()
|
|
124
|
+
resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
if (!confirmed) {
|
|
129
|
+
console.log('ā Transaction cancelled by user')
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log('\nš Broadcasting OP_RETURN transaction...')
|
|
134
|
+
|
|
135
|
+
// Prepare XEC outputs (optional)
|
|
136
|
+
let xecOutputs = []
|
|
137
|
+
if (xecAmount > 0) {
|
|
138
|
+
xecOutputs = [{
|
|
139
|
+
address: walletData.xecAddress,
|
|
140
|
+
amountSat: Math.round(xecAmount * 100)
|
|
141
|
+
}]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Send OP_RETURN transaction
|
|
145
|
+
const txid = await wallet.sendOpReturn(
|
|
146
|
+
message, // message
|
|
147
|
+
'6d02', // prefix (memo protocol)
|
|
148
|
+
xecOutputs, // optional XEC outputs
|
|
149
|
+
1.2 // sats per byte fee rate
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
console.log('\nā
OP_RETURN transaction sent successfully!')
|
|
153
|
+
console.log('ā'.repeat(60))
|
|
154
|
+
console.log(`Transaction ID: ${txid}`)
|
|
155
|
+
console.log(`Message: "${message}"`)
|
|
156
|
+
console.log(`Message Hex: ${messageHex}`)
|
|
157
|
+
console.log(`XEC Amount: ${xecAmount.toLocaleString()} XEC`)
|
|
158
|
+
console.log('ā'.repeat(60))
|
|
159
|
+
|
|
160
|
+
// Get updated balance
|
|
161
|
+
console.log('\nš° Getting updated balance...')
|
|
162
|
+
const newBalance = await wallet.getXecBalance()
|
|
163
|
+
const feePaid = balance - newBalance - xecAmount
|
|
164
|
+
|
|
165
|
+
console.log('\nš Transaction Summary:')
|
|
166
|
+
console.log(`Previous Balance: ${balance.toLocaleString()} XEC`)
|
|
167
|
+
console.log(`XEC Sent: ${xecAmount.toLocaleString()} XEC`)
|
|
168
|
+
console.log(`Fee Paid: ${feePaid.toLocaleString()} XEC`)
|
|
169
|
+
console.log(`New Balance: ${newBalance.toLocaleString()} XEC`)
|
|
170
|
+
|
|
171
|
+
console.log('\nš View Transaction:')
|
|
172
|
+
console.log(` Explorer: https://explorer.e.cash/tx/${txid}`)
|
|
173
|
+
console.log(' Note: Look for the OP_RETURN output in the transaction details')
|
|
174
|
+
|
|
175
|
+
console.log('\nš OP_RETURN Data Location:')
|
|
176
|
+
console.log(' ⢠Your message is now permanently stored on the XEC blockchain')
|
|
177
|
+
console.log(' ⢠Anyone can view it by examining the transaction')
|
|
178
|
+
console.log(' ⢠The data is in the OP_RETURN output of the transaction')
|
|
179
|
+
console.log(' ⢠Blockchain explorers will show the hex data')
|
|
180
|
+
|
|
181
|
+
console.log('\nš” Use Cases for OP_RETURN:')
|
|
182
|
+
console.log(' ⢠Document timestamping')
|
|
183
|
+
console.log(' ⢠Certificate verification')
|
|
184
|
+
console.log(' ⢠Digital signatures')
|
|
185
|
+
console.log(' ⢠Public announcements')
|
|
186
|
+
console.log(' ⢠Hash commitments')
|
|
187
|
+
|
|
188
|
+
// Ensure process exits cleanly
|
|
189
|
+
process.exit(0)
|
|
190
|
+
} catch (err) {
|
|
191
|
+
console.error('ā Failed to send OP_RETURN:', err.message)
|
|
192
|
+
|
|
193
|
+
// Provide helpful error context
|
|
194
|
+
if (err.message.includes('insufficient')) {
|
|
195
|
+
console.log('\nšø Insufficient Funds:')
|
|
196
|
+
console.log(' ⢠Your wallet does not have enough XEC for this transaction')
|
|
197
|
+
console.log(' ⢠OP_RETURN transactions still require fees')
|
|
198
|
+
console.log(' ⢠Try reducing the XEC amount or fund your wallet')
|
|
199
|
+
} else if (err.message.includes('size') || err.message.includes('large')) {
|
|
200
|
+
console.log('\nš Size Error:')
|
|
201
|
+
console.log(' ⢠Your message might be too large')
|
|
202
|
+
console.log(' ⢠Try a shorter message')
|
|
203
|
+
console.log(' ⢠Maximum recommended: 220 bytes')
|
|
204
|
+
} else if (err.message.includes('network')) {
|
|
205
|
+
console.log('\nš Network Error:')
|
|
206
|
+
console.log(' ⢠Check your internet connection')
|
|
207
|
+
console.log(' ⢠The network might be temporarily unavailable')
|
|
208
|
+
console.log(' ⢠Try again in a few moments')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
process.exit(1)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Run the example
|
|
216
|
+
sendOpReturn()
|