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,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()
|