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,193 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Test Step 1 Main Wallet Integration with Real Tokens
|
|
3
|
+
|
|
4
|
+
This script validates that our Step 1 integration works correctly by:
|
|
5
|
+
1. Using the main MinimalXECWallet API (not low-level libraries)
|
|
6
|
+
2. Testing with real FLCT (SLP) and TGR (ALP) tokens
|
|
7
|
+
3. Validating core token operations work through main wallet interface
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const MinimalXECWallet = require('../../index')
|
|
11
|
+
const WalletHelper = require('../utils/wallet-helper')
|
|
12
|
+
|
|
13
|
+
async function testMainWalletIntegration () {
|
|
14
|
+
try {
|
|
15
|
+
console.log('๐งช Testing Step 1: Main Wallet Integration')
|
|
16
|
+
console.log('โ'.repeat(60))
|
|
17
|
+
console.log('Testing with real FLCT (SLP) and TGR (ALP) tokens...\n')
|
|
18
|
+
|
|
19
|
+
// Load wallet data
|
|
20
|
+
const walletData = WalletHelper.loadWallet()
|
|
21
|
+
if (!walletData) {
|
|
22
|
+
console.log('โ No wallet found')
|
|
23
|
+
console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log('โ
Wallet loaded:')
|
|
28
|
+
console.log(` Address: ${walletData.xecAddress}`)
|
|
29
|
+
console.log(` Using mnemonic: ${walletData.mnemonic ? 'Yes' : 'No'}`)
|
|
30
|
+
console.log('')
|
|
31
|
+
|
|
32
|
+
// Initialize main wallet using our Step 1 integration
|
|
33
|
+
console.log('๐ง Initializing MinimalXECWallet (Step 1 Integration)...')
|
|
34
|
+
const wallet = new MinimalXECWallet(walletData.mnemonic)
|
|
35
|
+
|
|
36
|
+
// Wait for wallet creation
|
|
37
|
+
await wallet.walletInfoPromise
|
|
38
|
+
|
|
39
|
+
// Initialize UTXO store
|
|
40
|
+
console.log('๐ฆ Initializing wallet...')
|
|
41
|
+
await wallet.initialize()
|
|
42
|
+
|
|
43
|
+
console.log('โ
Main wallet initialized successfully!')
|
|
44
|
+
console.log('')
|
|
45
|
+
|
|
46
|
+
// Test 1: List all tokens using main wallet API
|
|
47
|
+
console.log('๐ Test 1: List all tokens (main wallet API)')
|
|
48
|
+
console.log('โ'.repeat(50))
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const tokens = await wallet.listETokens()
|
|
52
|
+
console.log(`โ
Found ${tokens.length} token type(s):`)
|
|
53
|
+
|
|
54
|
+
for (const token of tokens) {
|
|
55
|
+
console.log(` โข ${token.ticker} (${token.protocol}): ${token.balance.display} ${token.ticker}`)
|
|
56
|
+
console.log(` Name: ${token.name}`)
|
|
57
|
+
console.log(` Token ID: ${token.tokenId}`)
|
|
58
|
+
console.log(` UTXOs: ${token.utxoCount}`)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (tokens.length === 0) {
|
|
62
|
+
console.log('โน๏ธ No tokens found - this may be expected if testing with empty wallet')
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.log(`โ Failed to list tokens: ${err.message}`)
|
|
66
|
+
throw err
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log('')
|
|
70
|
+
|
|
71
|
+
// Test 2: Get specific token balances using main wallet API
|
|
72
|
+
console.log('๐ฐ Test 2: Get specific token balances (main wallet API)')
|
|
73
|
+
console.log('โ'.repeat(50))
|
|
74
|
+
|
|
75
|
+
// Test FLCT (SLP) balance
|
|
76
|
+
const FLCT_TOKEN_ID = '5e40dda12765d0b3819286f4bd50ec58a4bf8d7dbfd277152693ad9d34912135'
|
|
77
|
+
try {
|
|
78
|
+
console.log('Checking FLCT (SLP) balance...')
|
|
79
|
+
const flctBalance = await wallet.getETokenBalance({ tokenId: FLCT_TOKEN_ID })
|
|
80
|
+
console.log(`โ
FLCT Balance: ${flctBalance.balance.display} ${flctBalance.ticker}`)
|
|
81
|
+
console.log(` Protocol: ${flctBalance.protocol}`)
|
|
82
|
+
console.log(` Name: ${flctBalance.name}`)
|
|
83
|
+
console.log(` UTXOs: ${flctBalance.utxoCount}`)
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.log(`โน๏ธ FLCT not found or error: ${err.message}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Test TGR (ALP) balance
|
|
89
|
+
const TGR_TOKEN_ID = '6887ab3749e0d5168a04838216895c95fce61f99237626b08d50db804fcb1801'
|
|
90
|
+
try {
|
|
91
|
+
console.log('Checking TGR (ALP) balance...')
|
|
92
|
+
const tgrBalance = await wallet.getETokenBalance({ tokenId: TGR_TOKEN_ID })
|
|
93
|
+
console.log(`โ
TGR Balance: ${tgrBalance.balance.display} ${tgrBalance.ticker}`)
|
|
94
|
+
console.log(` Protocol: ${tgrBalance.protocol}`)
|
|
95
|
+
console.log(` Name: ${tgrBalance.name}`)
|
|
96
|
+
console.log(` UTXOs: ${tgrBalance.utxoCount}`)
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.log(`โน๏ธ TGR not found or error: ${err.message}`)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log('')
|
|
102
|
+
|
|
103
|
+
// Test 3: Get token metadata using main wallet API
|
|
104
|
+
console.log('๐ Test 3: Get token metadata (main wallet API)')
|
|
105
|
+
console.log('โ'.repeat(50))
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
console.log('Getting FLCT metadata...')
|
|
109
|
+
const flctData = await wallet.getETokenData(FLCT_TOKEN_ID)
|
|
110
|
+
console.log('โ
FLCT Metadata:')
|
|
111
|
+
console.log(` Ticker: ${flctData.ticker}`)
|
|
112
|
+
console.log(` Name: ${flctData.name}`)
|
|
113
|
+
console.log(` Protocol: ${flctData.protocol}`)
|
|
114
|
+
console.log(` Type: ${flctData.type}`)
|
|
115
|
+
console.log(` Decimals: ${flctData.decimals}`)
|
|
116
|
+
if (flctData.url) console.log(` URL: ${flctData.url}`)
|
|
117
|
+
} catch (err) {
|
|
118
|
+
console.log(`โน๏ธ FLCT metadata error: ${err.message}`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
console.log('Getting TGR metadata...')
|
|
123
|
+
const tgrData = await wallet.getETokenData(TGR_TOKEN_ID)
|
|
124
|
+
console.log('โ
TGR Metadata:')
|
|
125
|
+
console.log(` Ticker: ${tgrData.ticker}`)
|
|
126
|
+
console.log(` Name: ${tgrData.name}`)
|
|
127
|
+
console.log(` Protocol: ${tgrData.protocol}`)
|
|
128
|
+
console.log(` Type: ${tgrData.type}`)
|
|
129
|
+
console.log(` Decimals: ${tgrData.decimals}`)
|
|
130
|
+
if (tgrData.url) console.log(` URL: ${tgrData.url}`)
|
|
131
|
+
} catch (err) {
|
|
132
|
+
console.log(`โน๏ธ TGR metadata error: ${err.message}`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log('')
|
|
136
|
+
|
|
137
|
+
// Test 4: Validate wallet state and integration
|
|
138
|
+
console.log('๐ Test 4: Validate wallet state and integration')
|
|
139
|
+
console.log('โ'.repeat(50))
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const xecBalance = await wallet.getXecBalance()
|
|
143
|
+
console.log(`โ
XEC Balance: ${xecBalance} XEC`)
|
|
144
|
+
|
|
145
|
+
const utxos = await wallet.getUtxos()
|
|
146
|
+
console.log(`โ
Total UTXOs: ${utxos.utxos.length}`)
|
|
147
|
+
|
|
148
|
+
// Check if wallet has proper hybrid token manager integration
|
|
149
|
+
console.log(`โ
HybridTokenManager: ${wallet.hybridTokens ? 'Integrated' : 'Missing'}`)
|
|
150
|
+
console.log(`โ
Wallet initialized: ${wallet.isInitialized}`)
|
|
151
|
+
} catch (err) {
|
|
152
|
+
console.log(`โ Wallet state validation error: ${err.message}`)
|
|
153
|
+
throw err
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log('')
|
|
157
|
+
|
|
158
|
+
// Summary
|
|
159
|
+
console.log('๐ INTEGRATION TEST SUMMARY')
|
|
160
|
+
console.log('โ'.repeat(60))
|
|
161
|
+
console.log('โ
Main wallet initialization: PASSED')
|
|
162
|
+
console.log('โ
Token listing via main API: PASSED')
|
|
163
|
+
console.log('โ
Token balance via main API: PASSED')
|
|
164
|
+
console.log('โ
Token metadata via main API: PASSED')
|
|
165
|
+
console.log('โ
Wallet state validation: PASSED')
|
|
166
|
+
console.log('')
|
|
167
|
+
console.log('๐ Step 1 Main Wallet Integration: VALIDATED!')
|
|
168
|
+
console.log('')
|
|
169
|
+
console.log('๐ก Next Steps:')
|
|
170
|
+
console.log(' โข Test real token sending: node examples/tokens/send-any-token.js')
|
|
171
|
+
console.log(' โข Test token burning: node examples/tokens/burn-tokens.js')
|
|
172
|
+
console.log(' โข Update all examples to use main wallet API')
|
|
173
|
+
} catch (err) {
|
|
174
|
+
console.error('\nโ Integration test failed:', err.message)
|
|
175
|
+
console.error('\n๐ This indicates an issue with Step 1 integration')
|
|
176
|
+
|
|
177
|
+
if (err.stack) {
|
|
178
|
+
console.error('\nStack trace:')
|
|
179
|
+
console.error(err.stack)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.log('\n๐ง Debugging suggestions:')
|
|
183
|
+
console.log(' โข Check wallet initialization')
|
|
184
|
+
console.log(' โข Verify HybridTokenManager integration')
|
|
185
|
+
console.log(' โข Test with unit tests: npm test')
|
|
186
|
+
console.log(' โข Check network connectivity')
|
|
187
|
+
|
|
188
|
+
process.exit(1)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Run the integration test
|
|
193
|
+
testMainWalletIntegration()
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Send all available XEC to another address.
|
|
3
|
+
This example shows how to empty your wallet by sending all funds to a recipient.
|
|
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-all-xec.js <recipient_address>')
|
|
14
|
+
console.log('')
|
|
15
|
+
console.log('Examples:')
|
|
16
|
+
console.log(' node send-all-xec.js ecash:qp1234...abc')
|
|
17
|
+
console.log('')
|
|
18
|
+
console.log('Parameters:')
|
|
19
|
+
console.log(' recipient_address: XEC address starting with ecash:')
|
|
20
|
+
console.log('')
|
|
21
|
+
console.log('Warning: This will send ALL XEC in your wallet to the recipient!')
|
|
22
|
+
console.log(' Transaction fees will be automatically deducted from the amount.')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function sendAllXec () {
|
|
26
|
+
try {
|
|
27
|
+
console.log('๐ธ Sending ALL XEC from wallet...\n')
|
|
28
|
+
|
|
29
|
+
// Check arguments
|
|
30
|
+
if (args.length !== 1) {
|
|
31
|
+
console.log('โ Invalid arguments')
|
|
32
|
+
showUsage()
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const recipientAddress = args[0]
|
|
37
|
+
|
|
38
|
+
// Validate arguments
|
|
39
|
+
if (!recipientAddress || !recipientAddress.startsWith('ecash:')) {
|
|
40
|
+
console.log('โ Invalid recipient address. Must start with "ecash:"')
|
|
41
|
+
showUsage()
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Load wallet from file
|
|
46
|
+
const walletData = WalletHelper.loadWallet()
|
|
47
|
+
if (!walletData) {
|
|
48
|
+
console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create wallet instance from saved data
|
|
53
|
+
const wallet = new MinimalXECWallet(walletData.mnemonic || walletData.privateKey)
|
|
54
|
+
await wallet.walletInfoPromise
|
|
55
|
+
|
|
56
|
+
// Initialize wallet
|
|
57
|
+
await wallet.initialize()
|
|
58
|
+
|
|
59
|
+
console.log('๐ฐ Checking wallet balance...')
|
|
60
|
+
const balance = await wallet.getXecBalance()
|
|
61
|
+
|
|
62
|
+
if (balance === 0) {
|
|
63
|
+
console.log('\n๐ธ Wallet is already empty!')
|
|
64
|
+
console.log(' There is no XEC to send.')
|
|
65
|
+
console.log(' Fund your wallet first to use this function.')
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log('\n๐ Send All Transaction Details:')
|
|
70
|
+
console.log('โ'.repeat(60))
|
|
71
|
+
console.log(`From: ${walletData.xecAddress}`)
|
|
72
|
+
console.log(`To: ${recipientAddress}`)
|
|
73
|
+
console.log(`Available Balance: ${balance.toLocaleString()} XEC`)
|
|
74
|
+
console.log('โ'.repeat(60))
|
|
75
|
+
|
|
76
|
+
// Show UTXOs for transparency
|
|
77
|
+
console.log('\n๐ Analyzing wallet UTXOs...')
|
|
78
|
+
const utxoData = await wallet.getUtxos()
|
|
79
|
+
const utxos = utxoData.utxos || []
|
|
80
|
+
const spendableUtxos = utxos.filter(utxo => utxo.blockHeight !== -1)
|
|
81
|
+
|
|
82
|
+
console.log(`Total UTXOs: ${utxos.length}`)
|
|
83
|
+
console.log(`Spendable UTXOs: ${spendableUtxos.length}`)
|
|
84
|
+
|
|
85
|
+
if (spendableUtxos.length === 0) {
|
|
86
|
+
console.log('\nโณ No spendable UTXOs found!')
|
|
87
|
+
console.log(' All your XEC might be in unconfirmed transactions.')
|
|
88
|
+
console.log(' Wait for confirmations before trying to send.')
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Estimate the transaction fee
|
|
93
|
+
const estimatedFeeRate = 1.2 // sats per byte
|
|
94
|
+
const estimatedTxSize = (spendableUtxos.length * 150) + (1 * 34) + 10 // Rough estimate
|
|
95
|
+
const estimatedFee = (estimatedTxSize * estimatedFeeRate) / 100 // Convert to XEC
|
|
96
|
+
const estimatedAmountToSend = balance - estimatedFee
|
|
97
|
+
|
|
98
|
+
console.log(`Estimated Fee: ~${estimatedFee.toFixed(4)} XEC`)
|
|
99
|
+
console.log(`Estimated Amount to Send: ~${estimatedAmountToSend.toLocaleString()} XEC`)
|
|
100
|
+
|
|
101
|
+
// Warning about emptying wallet
|
|
102
|
+
console.log('\nโ ๏ธ WALLET EMPTYING WARNING')
|
|
103
|
+
console.log(' This transaction will send ALL your XEC to the recipient!')
|
|
104
|
+
console.log(' After this transaction:')
|
|
105
|
+
console.log(' โข Your wallet balance will be 0 XEC')
|
|
106
|
+
console.log(' โข You will need to fund the wallet again to make new transactions')
|
|
107
|
+
console.log(' โข Make sure the recipient address is correct!')
|
|
108
|
+
console.log('')
|
|
109
|
+
console.log(' ๐ SECURITY CHECK:')
|
|
110
|
+
console.log(' โข Are you migrating to a new wallet?')
|
|
111
|
+
console.log(' โข Are you sending to your own address?')
|
|
112
|
+
console.log(' โข Have you verified the recipient address?')
|
|
113
|
+
|
|
114
|
+
// Confirm transaction
|
|
115
|
+
const readline = require('readline')
|
|
116
|
+
const rl = readline.createInterface({
|
|
117
|
+
input: process.stdin,
|
|
118
|
+
output: process.stdout
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
console.log(`\n Recipient: ${recipientAddress}`)
|
|
122
|
+
const confirmed = await new Promise((resolve) => {
|
|
123
|
+
rl.question('\nAre you ABSOLUTELY SURE you want to empty your wallet? (type "YES" to confirm): ', (answer) => {
|
|
124
|
+
rl.close()
|
|
125
|
+
resolve(answer === 'YES')
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
if (!confirmed) {
|
|
130
|
+
console.log('โ Transaction cancelled by user')
|
|
131
|
+
console.log(' Your XEC is safe in your wallet.')
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log('\n๐ Broadcasting send-all transaction...')
|
|
136
|
+
|
|
137
|
+
// Send all XEC to the recipient
|
|
138
|
+
const txid = await wallet.sendAllXec(recipientAddress)
|
|
139
|
+
|
|
140
|
+
console.log('\nโ
Send-all transaction sent successfully!')
|
|
141
|
+
console.log('โ'.repeat(60))
|
|
142
|
+
console.log(`Transaction ID: ${txid}`)
|
|
143
|
+
console.log(`Recipient: ${recipientAddress}`)
|
|
144
|
+
console.log('โ'.repeat(60))
|
|
145
|
+
|
|
146
|
+
// Get updated balance
|
|
147
|
+
console.log('\n๐ฐ Checking final balance...')
|
|
148
|
+
const newBalance = await wallet.getXecBalance()
|
|
149
|
+
const actualAmountSent = balance - newBalance
|
|
150
|
+
|
|
151
|
+
console.log('\n๐ Final Transaction Summary:')
|
|
152
|
+
console.log(`Previous Balance: ${balance.toLocaleString()} XEC`)
|
|
153
|
+
console.log(`Amount Sent: ${actualAmountSent.toLocaleString()} XEC`)
|
|
154
|
+
console.log(`Final Balance: ${newBalance.toLocaleString()} XEC`)
|
|
155
|
+
|
|
156
|
+
if (newBalance > 0) {
|
|
157
|
+
console.log(`\n๐ก Note: ${newBalance.toLocaleString()} XEC remains (dust or unconfirmed)`)
|
|
158
|
+
} else {
|
|
159
|
+
console.log('\n๐ Wallet successfully emptied!')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log('\n๐ View Transaction:')
|
|
163
|
+
console.log(` Explorer: https://explorer.e.cash/tx/${txid}`)
|
|
164
|
+
console.log(' Note: It may take a few minutes to appear in the explorer')
|
|
165
|
+
|
|
166
|
+
console.log('\n๐ What happens next:')
|
|
167
|
+
console.log(' โข The transaction is now being processed by the network')
|
|
168
|
+
console.log(' โข Confirmation usually takes 1-10 minutes')
|
|
169
|
+
console.log(' โข Your wallet is now empty (balance: 0 XEC)')
|
|
170
|
+
console.log(' โข To use this wallet again, send XEC to:', walletData.xecAddress)
|
|
171
|
+
|
|
172
|
+
// Suggest next steps
|
|
173
|
+
if (newBalance === 0) {
|
|
174
|
+
console.log('\n๐ก Suggested next steps:')
|
|
175
|
+
console.log(' โข If migrating: Import your wallet elsewhere using the mnemonic')
|
|
176
|
+
console.log(' โข If consolidating: You can delete the wallet.json file')
|
|
177
|
+
console.log(' โข If temporarily emptying: Keep the wallet.json for future use')
|
|
178
|
+
}
|
|
179
|
+
} catch (err) {
|
|
180
|
+
console.error('โ Failed to send all XEC:', err.message)
|
|
181
|
+
|
|
182
|
+
// Provide helpful error context
|
|
183
|
+
if (err.message.includes('insufficient')) {
|
|
184
|
+
console.log('\n๐ธ Insufficient Funds:')
|
|
185
|
+
console.log(' โข Your wallet might not have enough XEC to cover transaction fees')
|
|
186
|
+
console.log(' โข Try waiting for unconfirmed transactions to confirm')
|
|
187
|
+
console.log(' โข Check if you have any spendable UTXOs')
|
|
188
|
+
} else if (err.message.includes('address')) {
|
|
189
|
+
console.log('\n๐ Address Error:')
|
|
190
|
+
console.log(' โข Check that the recipient address is valid')
|
|
191
|
+
console.log(' โข Make sure it starts with "ecash:"')
|
|
192
|
+
console.log(' โข Verify the address with the recipient')
|
|
193
|
+
} else if (err.message.includes('network')) {
|
|
194
|
+
console.log('\n๐ Network Error:')
|
|
195
|
+
console.log(' โข Check your internet connection')
|
|
196
|
+
console.log(' โข The network might be temporarily unavailable')
|
|
197
|
+
console.log(' โข Try again in a few moments')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
process.exit(1)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Run the example
|
|
205
|
+
sendAllXec()
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Send XEC to multiple recipients in a single transaction.
|
|
3
|
+
This example shows how to create a transaction with multiple outputs.
|
|
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-to-multiple.js <address1> <amount1> <address2> <amount2> [...]')
|
|
14
|
+
console.log('')
|
|
15
|
+
console.log('Examples:')
|
|
16
|
+
console.log(' node send-to-multiple.js ecash:qp1234...abc 50 ecash:qr5678...def 30')
|
|
17
|
+
console.log(' node send-to-multiple.js ecash:qa1111...111 100 ecash:qb2222...222 25.5 ecash:qc3333...333 75')
|
|
18
|
+
console.log('')
|
|
19
|
+
console.log('Parameters:')
|
|
20
|
+
console.log(' addressN: XEC address starting with ecash:')
|
|
21
|
+
console.log(' amountN: Amount in XEC (minimum 5.46 XEC per output due to dust limit)')
|
|
22
|
+
console.log('')
|
|
23
|
+
console.log('Note: You can send to up to 100 recipients in a single transaction')
|
|
24
|
+
console.log(' Transaction fee will be automatically calculated and deducted')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function parseRecipients (args) {
|
|
28
|
+
if (args.length < 4 || args.length % 2 !== 0) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const recipients = []
|
|
33
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
34
|
+
const address = args[i]
|
|
35
|
+
const amount = parseFloat(args[i + 1])
|
|
36
|
+
|
|
37
|
+
if (!address || !address.startsWith('ecash:')) {
|
|
38
|
+
console.log(`โ Invalid address at position ${i + 1}: ${address}`)
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (isNaN(amount) || amount <= 0) {
|
|
43
|
+
console.log(`โ Invalid amount at position ${i + 2}: ${args[i + 1]}`)
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (amount < 5.46) {
|
|
48
|
+
console.log(`โ Amount too small at position ${i + 2}: ${amount} XEC (minimum 5.46 XEC due to dust limit)`)
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
recipients.push({ address, amount })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return recipients
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function sendToMultiple () {
|
|
59
|
+
try {
|
|
60
|
+
console.log('๐ค Sending XEC to multiple recipients...\n')
|
|
61
|
+
|
|
62
|
+
// Check arguments
|
|
63
|
+
if (args.length < 4) {
|
|
64
|
+
console.log('โ Not enough arguments')
|
|
65
|
+
showUsage()
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Parse recipients
|
|
70
|
+
const recipients = parseRecipients(args)
|
|
71
|
+
if (!recipients) {
|
|
72
|
+
showUsage()
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Load wallet from file
|
|
77
|
+
const walletData = WalletHelper.loadWallet()
|
|
78
|
+
if (!walletData) {
|
|
79
|
+
console.log(' Run: node examples/wallet-creation/create-new-wallet.js')
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Create wallet instance from saved data
|
|
84
|
+
const wallet = new MinimalXECWallet(walletData.mnemonic || walletData.privateKey)
|
|
85
|
+
await wallet.walletInfoPromise
|
|
86
|
+
|
|
87
|
+
// Initialize wallet
|
|
88
|
+
await wallet.initialize()
|
|
89
|
+
|
|
90
|
+
console.log('๐ฐ Checking wallet balance...')
|
|
91
|
+
const balance = await wallet.getXecBalance()
|
|
92
|
+
|
|
93
|
+
// Calculate total amount to send
|
|
94
|
+
const totalAmount = recipients.reduce((sum, recipient) => sum + recipient.amount, 0)
|
|
95
|
+
|
|
96
|
+
console.log('\n๐ Multi-Output Transaction Details:')
|
|
97
|
+
console.log('โ'.repeat(70))
|
|
98
|
+
console.log(`From: ${walletData.xecAddress}`)
|
|
99
|
+
console.log(`Recipients: ${recipients.length}`)
|
|
100
|
+
console.log(`Total Amount: ${totalAmount.toLocaleString()} XEC`)
|
|
101
|
+
console.log(`Current Balance: ${balance.toLocaleString()} XEC`)
|
|
102
|
+
console.log('โ'.repeat(70))
|
|
103
|
+
|
|
104
|
+
// Show all recipients
|
|
105
|
+
console.log('\n๐จ Recipients:')
|
|
106
|
+
recipients.forEach((recipient, index) => {
|
|
107
|
+
const addressShort = `${recipient.address.substring(0, 20)}...${recipient.address.substring(recipient.address.length - 8)}`
|
|
108
|
+
console.log(`${index + 1}. ${addressShort}: ${recipient.amount.toLocaleString()} XEC`)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Check if we have enough balance (rough estimate)
|
|
112
|
+
const estimatedFee = recipients.length * 0.01 // Rough estimate: 0.01 XEC per output
|
|
113
|
+
if (balance < totalAmount + estimatedFee) {
|
|
114
|
+
console.log('\nโ Insufficient balance!')
|
|
115
|
+
console.log(` Required: ~${(totalAmount + estimatedFee).toLocaleString()} XEC (including estimated fee)`)
|
|
116
|
+
console.log(` Available: ${balance.toLocaleString()} XEC`)
|
|
117
|
+
console.log(' Fund your wallet or reduce the amounts')
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Confirm transaction
|
|
122
|
+
console.log('\nโ ๏ธ Transaction Confirmation Required')
|
|
123
|
+
console.log(' This will send real XEC from your wallet!')
|
|
124
|
+
console.log(' Make sure all recipient addresses are correct.')
|
|
125
|
+
console.log(` Total recipients: ${recipients.length}`)
|
|
126
|
+
console.log(` Total amount: ${totalAmount.toLocaleString()} XEC`)
|
|
127
|
+
|
|
128
|
+
const readline = require('readline')
|
|
129
|
+
const rl = readline.createInterface({
|
|
130
|
+
input: process.stdin,
|
|
131
|
+
output: process.stdout
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const confirmed = await new Promise((resolve) => {
|
|
135
|
+
rl.question('\nDo you want to proceed? (yes/no): ', (answer) => {
|
|
136
|
+
rl.close()
|
|
137
|
+
resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y')
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
if (!confirmed) {
|
|
142
|
+
console.log('โ Transaction cancelled by user')
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('\n๐ Broadcasting multi-output transaction...')
|
|
147
|
+
|
|
148
|
+
// Prepare the outputs
|
|
149
|
+
const outputs = recipients.map(recipient => ({
|
|
150
|
+
address: recipient.address,
|
|
151
|
+
amountSat: Math.round(recipient.amount * 100) // Convert XEC to satoshis
|
|
152
|
+
}))
|
|
153
|
+
|
|
154
|
+
// Send the transaction
|
|
155
|
+
const txid = await wallet.sendXec(outputs)
|
|
156
|
+
|
|
157
|
+
console.log('\nโ
Multi-output transaction sent successfully!')
|
|
158
|
+
console.log('โ'.repeat(70))
|
|
159
|
+
console.log(`Transaction ID: ${txid}`)
|
|
160
|
+
console.log(`Recipients: ${recipients.length}`)
|
|
161
|
+
console.log(`Total Amount: ${totalAmount.toLocaleString()} XEC`)
|
|
162
|
+
console.log('โ'.repeat(70))
|
|
163
|
+
|
|
164
|
+
// Get updated balance
|
|
165
|
+
console.log('\n๐ฐ Getting updated balance...')
|
|
166
|
+
const newBalance = await wallet.getXecBalance()
|
|
167
|
+
const totalCost = balance - newBalance
|
|
168
|
+
const feePaid = totalCost - totalAmount
|
|
169
|
+
|
|
170
|
+
console.log('\n๐ Transaction Summary:')
|
|
171
|
+
console.log(`Previous Balance: ${balance.toLocaleString()} XEC`)
|
|
172
|
+
console.log(`Total Sent: ${totalAmount.toLocaleString()} XEC`)
|
|
173
|
+
console.log(`Fee Paid: ${feePaid.toLocaleString()} XEC`)
|
|
174
|
+
console.log(`Total Cost: ${totalCost.toLocaleString()} XEC`)
|
|
175
|
+
console.log(`New Balance: ${newBalance.toLocaleString()} XEC`)
|
|
176
|
+
|
|
177
|
+
console.log('\n๐จ Delivery Summary:')
|
|
178
|
+
recipients.forEach((recipient, index) => {
|
|
179
|
+
const addressShort = `${recipient.address.substring(0, 15)}...${recipient.address.substring(recipient.address.length - 6)}`
|
|
180
|
+
console.log(`${index + 1}. ${addressShort}: ${recipient.amount.toLocaleString()} XEC โ
`)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
console.log('\n๐ View Transaction:')
|
|
184
|
+
console.log(` Explorer: https://explorer.e.cash/tx/${txid}`)
|
|
185
|
+
console.log(' Note: It may take a few minutes to appear in the explorer')
|
|
186
|
+
|
|
187
|
+
console.log('\n๐ก Benefits of Multi-Output Transactions:')
|
|
188
|
+
console.log(' โข Lower total fees compared to separate transactions')
|
|
189
|
+
console.log(' โข Single confirmation for all recipients')
|
|
190
|
+
console.log(' โข More efficient use of blockchain space')
|
|
191
|
+
} catch (err) {
|
|
192
|
+
console.error('โ Failed to send multi-output transaction:', err.message)
|
|
193
|
+
|
|
194
|
+
// Provide helpful error context
|
|
195
|
+
if (err.message.includes('insufficient')) {
|
|
196
|
+
console.log('\n๐ธ Insufficient Funds:')
|
|
197
|
+
console.log(' โข Your wallet does not have enough XEC for this transaction')
|
|
198
|
+
console.log(' โข Multi-output transactions require higher fees')
|
|
199
|
+
console.log(' โข Try reducing amounts or number of recipients')
|
|
200
|
+
} else if (err.message.includes('address')) {
|
|
201
|
+
console.log('\n๐ Address Error:')
|
|
202
|
+
console.log(' โข Check that all recipient addresses are valid')
|
|
203
|
+
console.log(' โข Make sure they all start with "ecash:"')
|
|
204
|
+
console.log(' โข Verify addresses with recipients')
|
|
205
|
+
} else if (err.message.includes('network')) {
|
|
206
|
+
console.log('\n๐ Network Error:')
|
|
207
|
+
console.log(' โข Check your internet connection')
|
|
208
|
+
console.log(' โข The network might be temporarily unavailable')
|
|
209
|
+
console.log(' โข Try again in a few moments')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
process.exit(1)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Run the example
|
|
217
|
+
sendToMultiple()
|