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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -0
  3. package/dist/minimal-xec-wallet.js +66268 -0
  4. package/dist/minimal-xec-wallet.min.js +55 -0
  5. package/examples/README.md +380 -0
  6. package/examples/advanced/browser-compatibility-test.js +263 -0
  7. package/examples/advanced/get-xec-price.js +149 -0
  8. package/examples/advanced/optimize-utxos.js +255 -0
  9. package/examples/advanced/send-op-return.js +216 -0
  10. package/examples/browser-test.html +350 -0
  11. package/examples/key-management/derive-addresses.js +191 -0
  12. package/examples/key-management/export-to-wif.js +114 -0
  13. package/examples/key-management/validate-address.js +214 -0
  14. package/examples/optimization/simple-consolidation-test.js +79 -0
  15. package/examples/optimization/test-utxo-consolidation.js +179 -0
  16. package/examples/test-examples.js +1204 -0
  17. package/examples/tokens/burn-tokens.js +293 -0
  18. package/examples/tokens/get-token-balance.js +169 -0
  19. package/examples/tokens/get-token-info.js +269 -0
  20. package/examples/tokens/list-all-tokens.js +162 -0
  21. package/examples/tokens/send-any-token.js +260 -0
  22. package/examples/tokens/test-main-wallet-integration.js +193 -0
  23. package/examples/transactions/send-all-xec.js +205 -0
  24. package/examples/transactions/send-to-multiple.js +217 -0
  25. package/examples/transactions/send-xec.js +191 -0
  26. package/examples/utils/show-qr.js +119 -0
  27. package/examples/utils/wallet-helper.js +176 -0
  28. package/examples/validation/comprehensive-infrastructure-test.js +210 -0
  29. package/examples/wallet-creation/create-new-wallet.js +67 -0
  30. package/examples/wallet-creation/import-from-wif.js +135 -0
  31. package/examples/wallet-creation/restore-from-mnemonic.js +100 -0
  32. package/examples/wallet-info/get-balance.js +99 -0
  33. package/examples/wallet-info/get-transactions.js +157 -0
  34. package/examples/wallet-info/get-utxos.js +145 -0
  35. package/examples/wallet.json +11 -0
  36. package/lib/adapters/robust-chronik-router.js +507 -0
  37. package/lib/adapters/router.js +651 -0
  38. package/lib/alp-token-handler.js +581 -0
  39. package/lib/browser-wasm-loader.js +271 -0
  40. package/lib/consolidate-utxos.js +338 -0
  41. package/lib/hybrid-token-manager.js +322 -0
  42. package/lib/key-derivation.js +466 -0
  43. package/lib/op-return.js +314 -0
  44. package/lib/security.js +270 -0
  45. package/lib/send-xec.js +396 -0
  46. package/lib/slp-token-handler.js +572 -0
  47. package/lib/token-protocol-detector.js +307 -0
  48. package/lib/utxos.js +303 -0
  49. package/package.json +125 -0
@@ -0,0 +1,269 @@
1
+ /*
2
+ Get comprehensive token information using the main wallet API
3
+ Demonstrates detailed metadata retrieval with automatic protocol detection
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 get-token-info.js <token_ticker_or_id>')
14
+ console.log('')
15
+ console.log('Examples:')
16
+ console.log(' node get-token-info.js FLCT')
17
+ console.log(' node get-token-info.js TGR')
18
+ console.log(' node get-token-info.js 5e40dda12765d0b3819286f4bd50ec58a4bf8d7dbfd277152693ad9d34912135')
19
+ console.log('')
20
+ console.log('Parameters:')
21
+ console.log(' token_ticker_or_id: Token ticker (FLCT, TGR) or full token ID')
22
+ console.log('')
23
+ console.log('✨ Features:')
24
+ console.log(' • Protocol (SLP/ALP) detected automatically')
25
+ console.log(' • Comprehensive token metadata')
26
+ console.log(' • Genesis information and timestamps')
27
+ console.log(' • Uses main wallet API for consistency')
28
+ console.log(' • Works with any token (even if not held in wallet)')
29
+ }
30
+
31
+ async function getTokenInfo () {
32
+ try {
33
+ console.log('📄 Get Token Information (Main Wallet API)...\n')
34
+
35
+ // Check arguments
36
+ if (args.length < 1) {
37
+ console.log('❌ Missing required arguments')
38
+ showUsage()
39
+ return
40
+ }
41
+
42
+ const tokenInput = args[0]
43
+
44
+ // Load wallet (for API access, not necessarily token holding)
45
+ const walletData = WalletHelper.loadWallet()
46
+ if (!walletData) {
47
+ console.log('❌ No wallet found')
48
+ console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
49
+ return
50
+ }
51
+
52
+ console.log('✅ Wallet loaded:')
53
+ console.log(` Address: ${walletData.xecAddress}`)
54
+ console.log('')
55
+
56
+ // Initialize main wallet (Step 1 integration)
57
+ console.log('🔧 Initializing wallet...')
58
+ const wallet = new MinimalXECWallet(walletData.mnemonic)
59
+
60
+ // Wait for wallet creation and initialization
61
+ await wallet.walletInfoPromise
62
+ await wallet.initialize()
63
+
64
+ console.log('✅ Wallet initialized successfully!')
65
+ console.log('')
66
+
67
+ // First, try to find token by listing wallet tokens
68
+ console.log('📦 Searching for token...')
69
+ const tokens = await wallet.listETokens()
70
+
71
+ // Find the token by ticker or ID
72
+ let selectedToken = null
73
+ let tokenId = null
74
+
75
+ // Try to match by ticker first (case-insensitive)
76
+ selectedToken = tokens.find(t =>
77
+ t.ticker.toLowerCase() === tokenInput.toLowerCase()
78
+ )
79
+
80
+ // If not found, try to match by token ID
81
+ if (!selectedToken) {
82
+ selectedToken = tokens.find(t => t.tokenId === tokenInput)
83
+ }
84
+
85
+ // If found in wallet tokens, use that info
86
+ if (selectedToken) {
87
+ tokenId = selectedToken.tokenId
88
+ console.log(`✅ Found token in wallet: ${selectedToken.ticker} (${selectedToken.protocol})`)
89
+ } else {
90
+ // If not found in wallet, assume it's a token ID
91
+ tokenId = tokenInput
92
+ console.log(`🔍 Token not found in wallet, trying as token ID: ${tokenId.substring(0, 12)}...`)
93
+ }
94
+
95
+ // Get comprehensive token data using main wallet API
96
+ console.log('\n📄 Getting comprehensive token information...')
97
+ const tokenData = await wallet.getETokenData(tokenId)
98
+
99
+ console.log('')
100
+ console.log('🎯 COMPREHENSIVE TOKEN INFORMATION:')
101
+ console.log('═'.repeat(70))
102
+
103
+ // Basic Information
104
+ console.log('📋 Basic Information:')
105
+ console.log(` Token ID: ${tokenData.tokenId}`)
106
+ console.log(` Ticker: ${tokenData.ticker}`)
107
+ console.log(` Name: ${tokenData.name}`)
108
+ console.log(` Protocol: ${tokenData.protocol}`)
109
+ console.log(` Type: ${tokenData.type}`)
110
+ console.log(` Decimals: ${tokenData.decimals}`)
111
+
112
+ // Links and Resources
113
+ if (tokenData.url) {
114
+ console.log('')
115
+ console.log('🔗 Links and Resources:')
116
+ console.log(` URL: ${tokenData.url}`)
117
+
118
+ // Provide context about URLs
119
+ if (tokenData.url.startsWith('ipfs://')) {
120
+ console.log(' Format: IPFS (decentralized storage)')
121
+ console.log(` Gateway: https://ipfs.io/ipfs/${tokenData.url.substring(7)}`)
122
+ } else if (tokenData.url.startsWith('http')) {
123
+ console.log(' Format: HTTP(S) web link')
124
+ } else {
125
+ console.log(' Format: Custom URL format')
126
+ }
127
+ }
128
+
129
+ // Additional Data
130
+ if (tokenData.data) {
131
+ console.log('')
132
+ console.log('💾 Additional Data:')
133
+ console.log(` Data: ${tokenData.data}`)
134
+
135
+ // Try to decode if it looks like hex
136
+ try {
137
+ if (tokenData.data.startsWith('0x') || tokenData.data.length % 2 === 0) {
138
+ const decoded = Buffer.from(tokenData.data.replace('0x', ''), 'hex').toString('utf8')
139
+ if (decoded.length > 0 && decoded.length < 100) {
140
+ console.log(` Decoded: ${decoded}`)
141
+ }
142
+ }
143
+ } catch (err) {
144
+ // Ignore decode errors
145
+ }
146
+ }
147
+
148
+ // Authority Information
149
+ if (tokenData.authPubkey) {
150
+ console.log('')
151
+ console.log('🔐 Authority Information:')
152
+ console.log(` Authority Pubkey: ${tokenData.authPubkey}`)
153
+ console.log(' Mint Authority: Present (can create more tokens)')
154
+ } else {
155
+ console.log('')
156
+ console.log('🔐 Authority Information:')
157
+ console.log(' Mint Authority: None (fixed supply token)')
158
+ }
159
+
160
+ // Timestamps
161
+ if (tokenData.timeFirstSeen) {
162
+ console.log('')
163
+ console.log('📅 Timeline:')
164
+ const firstSeen = new Date(tokenData.timeFirstSeen * 1000)
165
+ console.log(` First Seen: ${firstSeen.toLocaleString()}`)
166
+ console.log(` First Seen (UTC): ${firstSeen.toISOString()}`)
167
+
168
+ const daysSince = Math.floor((Date.now() - firstSeen.getTime()) / (1000 * 60 * 60 * 24))
169
+ console.log(` Age: ${daysSince} day(s) old`)
170
+ }
171
+
172
+ // Protocol-Specific Details
173
+ console.log('')
174
+ console.log(`📊 ${tokenData.protocol} Protocol Details:`)
175
+
176
+ if (tokenData.protocol === 'SLP') {
177
+ console.log(' Standard: Simple Ledger Protocol')
178
+ console.log(' Version: SLP v1')
179
+ console.log(' Consensus: Bitcoin Cash script validation')
180
+ console.log(' UTXO Model: Token amount stored in UTXO')
181
+ } else if (tokenData.protocol === 'ALP') {
182
+ console.log(' Standard: A Ledger Protocol')
183
+ console.log(' Version: ALP v1')
184
+ console.log(' Consensus: Native Bitcoin Cash consensus')
185
+ console.log(' UTXO Model: Atom-based precision')
186
+ console.log(' Script Type: eMPP (enhanced Memo Push Protocol)')
187
+ }
188
+
189
+ // Get balance if wallet holds this token
190
+ if (selectedToken) {
191
+ console.log('')
192
+ console.log('💰 Your Wallet Balance:')
193
+ console.log(` Balance: ${selectedToken.balance.display} ${selectedToken.ticker}`)
194
+ console.log(` Raw Atoms: ${selectedToken.balance.atoms}`)
195
+ console.log(` UTXOs: ${selectedToken.utxoCount}`)
196
+
197
+ if (selectedToken.balance.display > 0) {
198
+ console.log('')
199
+ console.log('💡 Available Actions:')
200
+ console.log(` • Send: node examples/tokens/send-any-token.js ${selectedToken.ticker} <address> <amount>`)
201
+ console.log(` • Burn: node examples/tokens/burn-tokens.js ${selectedToken.ticker} <amount>`)
202
+ console.log(` • Balance: node examples/tokens/get-token-balance.js ${selectedToken.ticker}`)
203
+ }
204
+ } else {
205
+ console.log('')
206
+ console.log('💰 Your Wallet Balance:')
207
+ console.log(' Balance: 0 (you do not hold this token)')
208
+ console.log('')
209
+ console.log('💡 How to get this token:')
210
+ console.log(' • Visit eCash token faucets')
211
+ console.log(' • Use decentralized exchanges (DEX)')
212
+ console.log(' • Receive from other wallets')
213
+ console.log(' • Purchase on supported exchanges')
214
+ }
215
+
216
+ // Explorer Links
217
+ console.log('')
218
+ console.log('🔗 Blockchain Explorer:')
219
+ console.log(` Token: https://explorer.e.cash/token/${tokenData.tokenId}`)
220
+ console.log(' View transactions, holders, and statistics')
221
+
222
+ // Additional Resources
223
+ console.log('')
224
+ console.log('📚 Additional Resources:')
225
+ if (tokenData.protocol === 'SLP') {
226
+ console.log(' • SLP Specification: https://slp.dev/')
227
+ console.log(' • SLP Token Registry: https://tokens.bch.sx/')
228
+ } else if (tokenData.protocol === 'ALP') {
229
+ console.log(' • ALP Specification: https://ecashbuilders.notion.site/')
230
+ console.log(' • eCash Documentation: https://docs.e.cash/')
231
+ }
232
+ console.log(' • eCash Explorer: https://explorer.e.cash/')
233
+ console.log(' • Chronik API: https://chronik.e.cash/')
234
+ } catch (err) {
235
+ console.error('\n❌ Failed to get token information:', err.message)
236
+
237
+ // Provide context-specific help based on error type
238
+ if (err.message.includes('Token ID is required')) {
239
+ console.log('\n🎯 Token ID Issue:')
240
+ console.log(' • Provide a valid token ticker or full token ID')
241
+ console.log(' • Check available tokens: node examples/tokens/list-all-tokens.js')
242
+ } else if (err.message.includes('not found') || err.message.includes('Invalid token ID')) {
243
+ console.log('\n🔍 Token Not Found:')
244
+ console.log(' • Verify token ticker or ID is correct')
245
+ console.log(' • Token may not exist on this network')
246
+ console.log(' • Check token ID format (64-character hex string)')
247
+ console.log(' • Try browsing tokens: https://explorer.e.cash/tokens')
248
+ } else if (err.message.includes('network') || err.message.includes('chronik')) {
249
+ console.log('\n🌐 Network Issue:')
250
+ console.log(' • Check internet connection')
251
+ console.log(' • Chronik API may be temporarily unavailable')
252
+ console.log(' • Try again in a few moments')
253
+ } else {
254
+ console.log('\n🔧 General Error:')
255
+ console.log(' • Check wallet is properly initialized')
256
+ console.log(' • Verify token exists on the network')
257
+ console.log(' • Try with a known token like FLCT or TGR')
258
+ }
259
+
260
+ console.log('\nFor debugging, try:')
261
+ console.log(' node examples/tokens/list-all-tokens.js')
262
+ console.log(' node examples/tokens/get-token-balance.js FLCT')
263
+
264
+ process.exit(1)
265
+ }
266
+ }
267
+
268
+ // Run the token info fetcher
269
+ getTokenInfo()
@@ -0,0 +1,162 @@
1
+ /*
2
+ List all tokens (SLP and ALP) in the wallet using the main wallet API
3
+ Demonstrates the unified eToken interface with automatic protocol detection
4
+ */
5
+
6
+ const MinimalXECWallet = require('../../index')
7
+ const WalletHelper = require('../utils/wallet-helper')
8
+
9
+ async function listAllTokens () {
10
+ try {
11
+ console.log('🪙 Listing All Tokens (SLP + ALP) - Main Wallet API...\n')
12
+
13
+ // Load wallet
14
+ const walletData = WalletHelper.loadWallet()
15
+ if (!walletData) {
16
+ console.log('❌ No wallet found')
17
+ console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
18
+ return
19
+ }
20
+
21
+ console.log('✅ Wallet loaded:')
22
+ console.log(` Address: ${walletData.xecAddress}`)
23
+ console.log('')
24
+
25
+ // Initialize main wallet (Step 1 integration)
26
+ console.log('🔧 Initializing wallet...')
27
+ const wallet = new MinimalXECWallet(walletData.mnemonic)
28
+
29
+ // Wait for wallet creation and initialization
30
+ await wallet.walletInfoPromise
31
+ await wallet.initialize()
32
+
33
+ console.log('✅ Wallet initialized successfully!')
34
+ console.log('')
35
+
36
+ // Get all tokens using main wallet API
37
+ console.log('📦 Scanning wallet for tokens...')
38
+ const tokens = await wallet.listETokens()
39
+
40
+ if (tokens.length === 0) {
41
+ console.log('ℹ️ No tokens found in wallet')
42
+
43
+ // Still show XEC balance
44
+ const xecBalance = await wallet.getXecBalance()
45
+ console.log('')
46
+ console.log('💰 Wallet Summary:')
47
+ console.log('═'.repeat(40))
48
+ console.log(`XEC Balance: ${xecBalance.toLocaleString()} XEC`)
49
+ console.log('Token Balance: 0 tokens')
50
+
51
+ console.log('\n💡 Get some tokens:')
52
+ console.log(' • Visit eCash faucets for test tokens')
53
+ console.log(' • Use DEX to trade for tokens')
54
+ console.log(' • Receive tokens from other wallets')
55
+ return
56
+ }
57
+
58
+ console.log(`🎯 Found ${tokens.length} token type(s):\n`)
59
+
60
+ // Display each token with full details
61
+ for (let i = 0; i < tokens.length; i++) {
62
+ const token = tokens[i]
63
+
64
+ console.log(`Token ${i + 1}: ${token.protocol} Protocol`)
65
+ console.log('═'.repeat(60))
66
+ console.log(`Token ID: ${token.tokenId}`)
67
+ console.log(`Ticker: ${token.ticker}`)
68
+ console.log(`Name: ${token.name}`)
69
+ console.log(`Protocol: ${token.protocol}`)
70
+ console.log(`Decimals: ${token.decimals}`)
71
+
72
+ if (token.url) {
73
+ console.log(`URL: ${token.url}`)
74
+ }
75
+
76
+ console.log('')
77
+ console.log('💰 Balance Information:')
78
+ console.log(` Display Balance: ${token.balance.display.toLocaleString()} ${token.ticker}`)
79
+ console.log(` Raw Atoms: ${token.balance.atoms}`)
80
+ console.log(` UTXOs: ${token.utxoCount}`)
81
+ console.log('')
82
+
83
+ // Show UTXO details if available
84
+ if (token.utxos && token.utxos.length > 0) {
85
+ console.log('📦 UTXO Details:')
86
+ for (let j = 0; j < token.utxos.length; j++) {
87
+ const utxo = token.utxos[j]
88
+ console.log(` UTXO ${j + 1}: ${utxo.outpoint.txid}:${utxo.outpoint.outIdx}`)
89
+ console.log(` Block: ${utxo.blockHeight === -1 ? 'Mempool' : utxo.blockHeight}`)
90
+ console.log(` Sats: ${utxo.sats} (dust)`)
91
+ console.log(` Atoms: ${utxo.token.atoms}`)
92
+ }
93
+ }
94
+
95
+ if (i < tokens.length - 1) {
96
+ console.log('\n' + '─'.repeat(60) + '\n')
97
+ }
98
+ }
99
+
100
+ // Get XEC balance and show comprehensive wallet summary
101
+ const xecBalance = await wallet.getXecBalance()
102
+ const utxos = await wallet.getUtxos()
103
+
104
+ console.log('\n📊 WALLET SUMMARY:')
105
+ console.log('═'.repeat(50))
106
+ console.log(`XEC Balance: ${xecBalance.toLocaleString()} XEC`)
107
+ console.log(`Total UTXOs: ${utxos.utxos.length}`)
108
+ console.log(`Token Types: ${tokens.length}`)
109
+
110
+ // Breakdown by protocol
111
+ const slpTokens = tokens.filter(t => t.protocol === 'SLP')
112
+ const alpTokens = tokens.filter(t => t.protocol === 'ALP')
113
+
114
+ if (slpTokens.length > 0) {
115
+ console.log(`SLP Tokens: ${slpTokens.length} types`)
116
+ slpTokens.forEach(token => {
117
+ console.log(` • ${token.ticker}: ${token.balance.display} ${token.ticker}`)
118
+ })
119
+ }
120
+
121
+ if (alpTokens.length > 0) {
122
+ console.log(`ALP Tokens: ${alpTokens.length} types`)
123
+ alpTokens.forEach(token => {
124
+ console.log(` • ${token.ticker}: ${token.balance.display} ${token.ticker}`)
125
+ })
126
+ }
127
+
128
+ const isMultiProtocol = slpTokens.length > 0 && alpTokens.length > 0
129
+ console.log(`Multi-Protocol Wallet: ${isMultiProtocol ? 'Yes' : 'No'}`)
130
+
131
+ console.log('\n💡 Available Operations:')
132
+ console.log(' • Send tokens: node examples/tokens/send-any-token.js <ticker> <address> <amount>')
133
+ console.log(' • Get token balance: node examples/tokens/get-token-balance.js <ticker>')
134
+ console.log(' • Get token info: node examples/tokens/get-token-info.js <ticker>')
135
+ console.log(' • Burn tokens: node examples/tokens/burn-tokens.js <ticker> <amount>')
136
+ } catch (err) {
137
+ console.error('❌ Failed to list tokens:', err.message)
138
+
139
+ // Provide helpful debugging information
140
+ if (err.message.includes('wallet not initialized')) {
141
+ console.log('\n🔧 Wallet initialization issue:')
142
+ console.log(' • Check wallet.json exists')
143
+ console.log(' • Verify mnemonic is valid')
144
+ console.log(' • Try re-creating wallet')
145
+ } else if (err.message.includes('network') || err.message.includes('chronik')) {
146
+ console.log('\n🌐 Network issue:')
147
+ console.log(' • Check internet connection')
148
+ console.log(' • Chronik API may be temporarily unavailable')
149
+ console.log(' • Try again in a few moments')
150
+ } else {
151
+ console.log('\n📍 Error details:')
152
+ if (err.stack) {
153
+ console.error('Stack trace:', err.stack)
154
+ }
155
+ }
156
+
157
+ process.exit(1)
158
+ }
159
+ }
160
+
161
+ // Run the token listing
162
+ listAllTokens()
@@ -0,0 +1,260 @@
1
+ /*
2
+ Send any token (SLP or ALP) using the main wallet API
3
+ Demonstrates automatic protocol detection and unified token sending interface
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-any-token.js <token_ticker_or_id> <recipient> <amount>')
14
+ console.log('')
15
+ console.log('Examples:')
16
+ console.log(' node send-any-token.js FLCT ecash:qpcskwl402g5stqxy26js0j3mx5v54xqtssp0v7kkr 2')
17
+ console.log(' node send-any-token.js TGR etoken:qpcskwl402g5stqxy26js0j3mx5v54xqtssp0v7kkr 3')
18
+ console.log(' node send-any-token.js 5e40dda12765...912135 ecash:qpcskwl402g5stqxy26js0j3mx5v54xqtssp0v7kkr 1')
19
+ console.log('')
20
+ console.log('Parameters:')
21
+ console.log(' token_ticker_or_id: Token ticker (FLCT, TGR) or full token ID')
22
+ console.log(' recipient: eCash address (ecash: or etoken: format)')
23
+ console.log(' amount: Amount to send (in display units)')
24
+ console.log('')
25
+ console.log('✨ Features:')
26
+ console.log(' • Protocol (SLP/ALP) detected automatically')
27
+ console.log(' • Uses main wallet API for consistency')
28
+ console.log(' • Unified error handling and validation')
29
+ }
30
+
31
+ async function sendAnyToken () {
32
+ try {
33
+ console.log('🚀 Sending Token (Main Wallet API)...\n')
34
+
35
+ // Check arguments
36
+ if (args.length < 3) {
37
+ console.log('❌ Missing required arguments')
38
+ showUsage()
39
+ return
40
+ }
41
+
42
+ const tokenInput = args[0]
43
+ const recipient = args[1]
44
+ const amount = parseFloat(args[2])
45
+
46
+ // Validate amount
47
+ if (isNaN(amount) || amount <= 0) {
48
+ console.log('❌ Invalid amount. Must be a positive number')
49
+ showUsage()
50
+ return
51
+ }
52
+
53
+ // Load wallet
54
+ const walletData = WalletHelper.loadWallet()
55
+ if (!walletData) {
56
+ console.log('❌ No wallet found')
57
+ console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
58
+ return
59
+ }
60
+
61
+ console.log('✅ Wallet loaded:')
62
+ console.log(` Address: ${walletData.xecAddress}`)
63
+ console.log('')
64
+
65
+ // Initialize main wallet (Step 1 integration)
66
+ console.log('🔧 Initializing wallet...')
67
+ const wallet = new MinimalXECWallet(walletData.mnemonic)
68
+
69
+ // Wait for wallet creation and initialization
70
+ await wallet.walletInfoPromise
71
+ await wallet.initialize()
72
+
73
+ console.log('✅ Wallet initialized successfully!')
74
+ console.log('')
75
+
76
+ // Get available tokens using main wallet API
77
+ console.log('📦 Loading available tokens...')
78
+ const tokens = await wallet.listETokens()
79
+
80
+ if (tokens.length === 0) {
81
+ console.log('❌ No tokens found in wallet')
82
+ console.log('')
83
+ console.log('💡 Get some tokens:')
84
+ console.log(' • Visit eCash faucets for test tokens')
85
+ console.log(' • Use DEX to trade for tokens')
86
+ console.log(' • Receive tokens from other wallets')
87
+ return
88
+ }
89
+
90
+ console.log(`✅ Found ${tokens.length} token type(s):`)
91
+ for (const token of tokens) {
92
+ console.log(` • ${token.ticker} (${token.protocol}): ${token.balance.display} ${token.ticker}`)
93
+ }
94
+ console.log('')
95
+
96
+ // Find the token to send
97
+ let selectedToken = null
98
+
99
+ // Try to match by ticker first (case-insensitive)
100
+ selectedToken = tokens.find(t =>
101
+ t.ticker.toLowerCase() === tokenInput.toLowerCase()
102
+ )
103
+
104
+ // If not found, try to match by token ID
105
+ if (!selectedToken) {
106
+ selectedToken = tokens.find(t => t.tokenId === tokenInput)
107
+ }
108
+
109
+ if (!selectedToken) {
110
+ console.log(`❌ Token "${tokenInput}" not found in wallet`)
111
+ console.log(`Available tokens: ${tokens.map(t => t.ticker).join(', ')}`)
112
+ return
113
+ }
114
+
115
+ console.log('🎯 Selected Token:')
116
+ console.log('═'.repeat(50))
117
+ console.log(`Ticker: ${selectedToken.ticker}`)
118
+ console.log(`Name: ${selectedToken.name}`)
119
+ console.log(`Protocol: ${selectedToken.protocol}`)
120
+ console.log(`Token ID: ${selectedToken.tokenId}`)
121
+ console.log(`Current Balance: ${selectedToken.balance.display} ${selectedToken.ticker}`)
122
+ console.log(`Decimals: ${selectedToken.decimals}`)
123
+ console.log('')
124
+
125
+ // Validate sufficient balance
126
+ if (selectedToken.balance.display < amount) {
127
+ console.log('❌ Insufficient token balance!')
128
+ console.log(` Requested: ${amount} ${selectedToken.ticker}`)
129
+ console.log(` Available: ${selectedToken.balance.display} ${selectedToken.ticker}`)
130
+ return
131
+ }
132
+
133
+ // Convert etoken: to ecash: format if needed
134
+ let recipientAddress = recipient
135
+ if (recipient.startsWith('etoken:')) {
136
+ recipientAddress = 'ecash:' + recipient.substring(7)
137
+ }
138
+
139
+ console.log(`📍 Recipient: ${recipientAddress}`)
140
+
141
+ // Get current XEC balance for fee check
142
+ const xecBalance = await wallet.getXecBalance()
143
+ console.log(`💰 XEC Available: ${xecBalance.toLocaleString()} XEC`)
144
+
145
+ if (xecBalance < 1) {
146
+ console.log('⚠️ Warning: Low XEC balance for transaction fees')
147
+ }
148
+
149
+ // Show transaction summary
150
+ console.log('\n📋 Transaction Summary:')
151
+ console.log('═'.repeat(50))
152
+ console.log(`Protocol: ${selectedToken.protocol}`)
153
+ console.log(`Token: ${selectedToken.ticker} (${selectedToken.name})`)
154
+ console.log(`From: ${walletData.xecAddress}`)
155
+ console.log(`To: ${recipientAddress}`)
156
+ console.log(`Amount: ${amount} ${selectedToken.ticker}`)
157
+ console.log(`Remaining: ${(selectedToken.balance.display - amount).toFixed(selectedToken.decimals)} ${selectedToken.ticker}`)
158
+ console.log('Estimated Fee: ~0.01 XEC')
159
+
160
+ // Confirm transaction
161
+ const readline = require('readline')
162
+ const rl = readline.createInterface({
163
+ input: process.stdin,
164
+ output: process.stdout
165
+ })
166
+
167
+ const confirmed = await new Promise((resolve) => {
168
+ rl.question('\nDo you want to proceed with this token transfer? (yes/no): ', (answer) => {
169
+ rl.close()
170
+ resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
171
+ })
172
+ })
173
+
174
+ if (!confirmed) {
175
+ console.log('❌ Transaction cancelled by user')
176
+ return
177
+ }
178
+
179
+ console.log('\n🚀 Broadcasting token transaction...')
180
+ console.log(` Protocol: ${selectedToken.protocol}`)
181
+ console.log(' Using main wallet API with automatic protocol routing')
182
+
183
+ // Prepare outputs for main wallet API
184
+ const outputs = [{
185
+ address: recipientAddress,
186
+ amount: amount
187
+ }]
188
+
189
+ // Send the tokens using main wallet API (Step 1 integration)
190
+ // The wallet will automatically:
191
+ // - Detect the protocol (SLP/ALP)
192
+ // - Route to appropriate handler
193
+ // - Handle UTXO selection
194
+ // - Build and broadcast transaction
195
+ const txid = await wallet.sendETokens(
196
+ selectedToken.tokenId,
197
+ outputs,
198
+ 1.2 // sats per byte fee rate
199
+ )
200
+
201
+ console.log('\n✅ Token transaction sent successfully!')
202
+ console.log('═'.repeat(60))
203
+ console.log(`Transaction ID: ${txid}`)
204
+ console.log(`Protocol: ${selectedToken.protocol}`)
205
+ console.log(`Token: ${selectedToken.ticker}`)
206
+ console.log(`Amount: ${amount} ${selectedToken.ticker}`)
207
+ console.log(`To: ${recipientAddress}`)
208
+ console.log('═'.repeat(60))
209
+
210
+ console.log('\n🔗 View Transaction:')
211
+ console.log(` Explorer: https://explorer.e.cash/tx/${txid}`)
212
+
213
+ console.log('\n💰 Updated Balances (estimated):')
214
+ console.log(` ${selectedToken.ticker}: ${(selectedToken.balance.display - amount).toFixed(selectedToken.decimals)} ${selectedToken.ticker}`)
215
+ console.log(` XEC: ~${(xecBalance - 0.01).toFixed(2)} XEC (minus fees)`)
216
+
217
+ console.log('\n💡 Next Steps:')
218
+ console.log(' • Check updated balance: node examples/tokens/list-all-tokens.js')
219
+ console.log(' • Send more tokens: node examples/tokens/send-any-token.js')
220
+ console.log(' • Get token info: node examples/tokens/get-token-info.js')
221
+ } catch (err) {
222
+ console.error('\n❌ Failed to send token:', err.message)
223
+
224
+ // Provide context-specific help based on error type
225
+ if (err.message.includes('Token ID is required')) {
226
+ console.log('\n🎯 Token Selection Issue:')
227
+ console.log(' • Verify token ticker or ID is correct')
228
+ console.log(' • Check available tokens: node examples/tokens/list-all-tokens.js')
229
+ } else if (err.message.includes('insufficient')) {
230
+ console.log('\n💸 Balance Issue:')
231
+ console.log(' • Check token balance is sufficient')
232
+ console.log(' • Ensure XEC available for fees')
233
+ console.log(' • Balance check: node examples/tokens/list-all-tokens.js')
234
+ } else if (err.message.includes('address') || err.message.includes('Invalid address')) {
235
+ console.log('\n📍 Address Issue:')
236
+ console.log(' • Verify recipient address format')
237
+ console.log(' • Use ecash: or etoken: format')
238
+ console.log(' • Example: ecash:qpcskwl402g5stqxy26js0j3mx5v54xqtssp0v7kkr')
239
+ } else if (err.message.includes('network') || err.message.includes('chronik')) {
240
+ console.log('\n🌐 Network Issue:')
241
+ console.log(' • Check internet connection')
242
+ console.log(' • Chronik API may be temporarily unavailable')
243
+ console.log(' • Try again in a few moments')
244
+ } else {
245
+ console.log('\n🔧 General Error:')
246
+ console.log(' • Check wallet is properly initialized')
247
+ console.log(' • Verify wallet has tokens and XEC for fees')
248
+ console.log(' • Try listing tokens first to debug')
249
+ }
250
+
251
+ console.log('\nFor debugging, run:')
252
+ console.log(' node examples/tokens/list-all-tokens.js')
253
+ console.log(' node examples/wallet-info/get-balance.js')
254
+
255
+ process.exit(1)
256
+ }
257
+ }
258
+
259
+ // Run the token sender
260
+ sendAnyToken()