hodl-wallet 1.4.6 β 1.5.4
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/README.md +24 -2
- package/index.mjs +46 -14
- package/network/arb.js +10 -0
- package/network/avax.js +10 -0
- package/network/ftm.js +10 -0
- package/network/op.js +10 -0
- package/network/pol.js +2 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -41,9 +41,19 @@ Keep your favorite addresses handy. No more copy-pasting!
|
|
|
41
41
|
|
|
42
42
|
### π Multi-Network Support
|
|
43
43
|
|
|
44
|
-
Seamlessly manage your assets on
|
|
44
|
+
Seamlessly manage your assets on multiple networks. HODL Wallet supports the following networks:
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
- Binance Smart Chain
|
|
47
|
+
- Ethereum
|
|
48
|
+
- Polygon
|
|
49
|
+
- Optimism
|
|
50
|
+
- Arbitrum One
|
|
51
|
+
- Fantom
|
|
52
|
+
- Avalanche C-Chain
|
|
53
|
+
|
|
54
|
+
Each network supports its native token and popular tokens like USDT. You can easily add more tokens as needed.
|
|
55
|
+
|
|
56
|
+
## πΎ Export and Import HODL Files
|
|
47
57
|
|
|
48
58
|
HODL Wallet now supports exporting and importing encrypted .HODL files, which securely store your wallet information.
|
|
49
59
|
|
|
@@ -83,6 +93,18 @@ We've carefully selected trusted and well-maintained dependencies for this proje
|
|
|
83
93
|
|
|
84
94
|
β οΈ **Important Notice**: HODL Wallet is a personal project created with the best intentions. While we strive for security, it may contain security flaws or vulnerabilities. Use at your own risk and always exercise caution with your crypto assets.
|
|
85
95
|
|
|
96
|
+
## π What HODL means
|
|
97
|
+
|
|
98
|
+
The term "HODL" is a cornerstone of crypto culture, and it's worth understanding its origins:
|
|
99
|
+
|
|
100
|
+
- π Born on December 18, 2013, in a Bitcoin Talk forum post
|
|
101
|
+
- πΊ Originally a typo for "HOLD" in a drunk, impassioned rant about not selling Bitcoin
|
|
102
|
+
- π€ Later backronymed to mean "Hold On for Dear Life"
|
|
103
|
+
- π Symbolizes a long-term investment strategy and resistance to panic selling
|
|
104
|
+
- π Now used across various cryptocurrency communities as a rallying cry
|
|
105
|
+
|
|
106
|
+
HODL embodies the belief in the long-term potential of cryptocurrencies, often in the face of short-term market volatility. It's more than just a misspelling; it's a philosophy that has shaped the crypto landscape.
|
|
107
|
+
|
|
86
108
|
## π€ Contributing
|
|
87
109
|
|
|
88
110
|
Found a bug? Want to add a feature? We're all ears! Open an issue or submit a PR. Let's make crypto easier together.
|
package/index.mjs
CHANGED
|
@@ -36,6 +36,7 @@ class Wallet {
|
|
|
36
36
|
this.web3 = null;
|
|
37
37
|
this.selectedNetwork = null;
|
|
38
38
|
this.account = null;
|
|
39
|
+
this.networkUsage = this.db.get('networkUsage') || {};
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
async initialize() {
|
|
@@ -84,14 +85,23 @@ class Wallet {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
async selectNetwork(networkPlugins) {
|
|
88
|
+
// Sort networks by usage count (descending)
|
|
89
|
+
const sortedNetworks = networkPlugins.sort((a, b) =>
|
|
90
|
+
(this.networkUsage[b.name] || 0) - (this.networkUsage[a.name] || 0)
|
|
91
|
+
);
|
|
92
|
+
|
|
87
93
|
const { network } = await inquirer.prompt({
|
|
88
94
|
type: 'list',
|
|
89
95
|
name: 'network',
|
|
90
96
|
message: 'Select the network:',
|
|
91
|
-
choices:
|
|
97
|
+
choices: sortedNetworks.map(plugin => plugin.name),
|
|
92
98
|
});
|
|
93
99
|
|
|
94
|
-
const selectedNetwork =
|
|
100
|
+
const selectedNetwork = sortedNetworks.find(plugin => plugin.name === network);
|
|
101
|
+
|
|
102
|
+
// Increment usage count for the selected network
|
|
103
|
+
this.networkUsage[network] = (this.networkUsage[network] || 0) + 1;
|
|
104
|
+
this.db.set('networkUsage', this.networkUsage);
|
|
95
105
|
|
|
96
106
|
this.selectedNetwork = selectedNetwork;
|
|
97
107
|
}
|
|
@@ -291,7 +301,12 @@ class Wallet {
|
|
|
291
301
|
}
|
|
292
302
|
|
|
293
303
|
async transferFunds() {
|
|
294
|
-
const
|
|
304
|
+
const contacts = this.db.get('contact') || {};
|
|
305
|
+
const addressBook = Object.entries(contacts).map(([address, data]) => ({
|
|
306
|
+
address,
|
|
307
|
+
name: data.name
|
|
308
|
+
}));
|
|
309
|
+
|
|
295
310
|
addressBook.push({ name: 'Go Back', address: '' });
|
|
296
311
|
|
|
297
312
|
// Implement autocomplete for address book
|
|
@@ -327,7 +342,7 @@ class Wallet {
|
|
|
327
342
|
const { amount } = await inquirer.prompt({
|
|
328
343
|
type: 'input',
|
|
329
344
|
name: 'amount',
|
|
330
|
-
message: `Amount to transfer
|
|
345
|
+
message: `Amount to transfer:`,
|
|
331
346
|
validate: value => {
|
|
332
347
|
if (value === '') return true;
|
|
333
348
|
return !isNaN(value) && Number(value) > 0 ? true : 'Please enter a valid number or leave empty to cancel.';
|
|
@@ -338,6 +353,18 @@ class Wallet {
|
|
|
338
353
|
return;
|
|
339
354
|
}
|
|
340
355
|
|
|
356
|
+
// Add confirmation step
|
|
357
|
+
const { confirmTransaction } = await inquirer.prompt({
|
|
358
|
+
type: 'confirm',
|
|
359
|
+
name: 'confirmTransaction',
|
|
360
|
+
message: `Confirm transfer?`,
|
|
361
|
+
default: true
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
if (!confirmTransaction) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
341
368
|
try {
|
|
342
369
|
let signedTx;
|
|
343
370
|
if (tokens[token] && token !== this.selectedNetwork.nativeToken) {
|
|
@@ -352,7 +379,7 @@ class Wallet {
|
|
|
352
379
|
// Add transaction to history
|
|
353
380
|
this.addToTransactions(address, token, amount, receipt.transactionHash);
|
|
354
381
|
|
|
355
|
-
if (!
|
|
382
|
+
if (!contacts[address]) {
|
|
356
383
|
await this.addToAddressBook(address);
|
|
357
384
|
}
|
|
358
385
|
|
|
@@ -416,7 +443,10 @@ class Wallet {
|
|
|
416
443
|
|
|
417
444
|
history.forEach(tx => {
|
|
418
445
|
const date = this.formatDate(tx.timestamp);
|
|
419
|
-
|
|
446
|
+
const contact = this.db.get('contact', tx.recipient);
|
|
447
|
+
const recipient = contact ? `${tx.recipient} (${contact.name})` : tx.recipient;
|
|
448
|
+
const amount = parseFloat(tx.amount).toFixed(3);
|
|
449
|
+
table.push([date, recipient, tx.token, amount]);
|
|
420
450
|
table.push([{ colSpan: 4, content: this.selectedNetwork.explorer + tx.hash }]);
|
|
421
451
|
});
|
|
422
452
|
|
|
@@ -431,9 +461,8 @@ class Wallet {
|
|
|
431
461
|
});
|
|
432
462
|
|
|
433
463
|
if (name.trim() !== '') {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
this.db.set('addressBook', addressBook);
|
|
464
|
+
|
|
465
|
+
this.db.set('contact', address, 'name', name);
|
|
437
466
|
|
|
438
467
|
const table = new Table({
|
|
439
468
|
head: [{ colSpan: 2, content: "Recipient saved to the address book." }],
|
|
@@ -536,9 +565,12 @@ class Wallet {
|
|
|
536
565
|
|
|
537
566
|
const date = this.formatDate(new Date());
|
|
538
567
|
|
|
568
|
+
const contact = this.db.get('contact', address);
|
|
569
|
+
const recipient = contact ? `${address} (${contact.name})` : address;
|
|
570
|
+
|
|
539
571
|
table.push([
|
|
540
572
|
date,
|
|
541
|
-
|
|
573
|
+
recipient,
|
|
542
574
|
token,
|
|
543
575
|
parseFloat(amount).toFixed(3)
|
|
544
576
|
]);
|
|
@@ -822,9 +854,9 @@ while (true) {
|
|
|
822
854
|
name: 'action',
|
|
823
855
|
message: 'What would you like to do?',
|
|
824
856
|
choices: [
|
|
825
|
-
{ name: 'Transfer Funds', value: '
|
|
857
|
+
{ name: 'Transfer Funds', value: 'transferFunds' },
|
|
826
858
|
{ name: 'Show Balance', value: 'balance' },
|
|
827
|
-
{ name: 'Show Sent Transfers', value: '
|
|
859
|
+
{ name: 'Show Sent Transfers', value: 'showTransactions' },
|
|
828
860
|
{ name: 'Account Settings', value: 'account' },
|
|
829
861
|
{ name: 'Exit', value: 'exit' }
|
|
830
862
|
],
|
|
@@ -834,10 +866,10 @@ while (true) {
|
|
|
834
866
|
case 'balance':
|
|
835
867
|
await wallet.showBalance();
|
|
836
868
|
break;
|
|
837
|
-
case '
|
|
869
|
+
case 'transferFunds':
|
|
838
870
|
await wallet.transferFunds();
|
|
839
871
|
break;
|
|
840
|
-
case '
|
|
872
|
+
case 'showTransactions':
|
|
841
873
|
await wallet.showTransactions();
|
|
842
874
|
break;
|
|
843
875
|
case 'account':
|
package/network/arb.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
name: '[ERC-20] Arbitrum One',
|
|
3
|
+
explorer: 'https://arbiscan.io/tx/',
|
|
4
|
+
rpcUrl: 'https://arb1.arbitrum.io/rpc',
|
|
5
|
+
nativeToken: 'ETH',
|
|
6
|
+
tokens: {
|
|
7
|
+
'USDT': '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', // USDT on Arbitrum
|
|
8
|
+
'ARB': '0x0000000000000000000000000000000000000000', // Native ETH on Arbitrum
|
|
9
|
+
},
|
|
10
|
+
};
|
package/network/avax.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
name: '[ERC-20] Avalanche C-Chain',
|
|
3
|
+
explorer: 'https://snowtrace.io/tx/',
|
|
4
|
+
rpcUrl: 'https://api.avax.network/ext/bc/C/rpc',
|
|
5
|
+
nativeToken: 'AVAX',
|
|
6
|
+
tokens: {
|
|
7
|
+
'USDT': '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7', // USDT.e on Avalanche C-Chain
|
|
8
|
+
'AVAX': '0x0000000000000000000000000000000000000000', // Native AVAX
|
|
9
|
+
},
|
|
10
|
+
};
|
package/network/ftm.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
name: '[ERC-20] Fantom',
|
|
3
|
+
explorer: 'https://ftmscan.com/tx/',
|
|
4
|
+
rpcUrl: 'https://rpc.ftm.tools/',
|
|
5
|
+
nativeToken: 'FTM',
|
|
6
|
+
tokens: {
|
|
7
|
+
'USDT': '0x049d68029688eAbF473097a2fC38ef61633A3C7A', // USDT on Fantom
|
|
8
|
+
'FTM': '0x0000000000000000000000000000000000000000', // Native FTM
|
|
9
|
+
},
|
|
10
|
+
};
|
package/network/op.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
name: '[ERC-20] Optimism',
|
|
3
|
+
explorer: 'https://optimistic.etherscan.io/tx/',
|
|
4
|
+
rpcUrl: 'https://mainnet.optimism.io',
|
|
5
|
+
nativeToken: 'ETH',
|
|
6
|
+
tokens: {
|
|
7
|
+
'USDT': '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', // USDT on Optimism
|
|
8
|
+
'OP': '0x0000000000000000000000000000000000000000',
|
|
9
|
+
},
|
|
10
|
+
};
|
package/network/pol.js
CHANGED
|
@@ -5,6 +5,7 @@ module.exports = {
|
|
|
5
5
|
rpcUrl: 'https://polygon-rpc.com/',
|
|
6
6
|
nativeToken: 'POL',
|
|
7
7
|
tokens: {
|
|
8
|
-
'USDT': '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
8
|
+
'USDT': '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
9
|
+
'POL': '0x0000000000000000000000000000000000000000',
|
|
9
10
|
},
|
|
10
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hodl-wallet",
|
|
3
|
-
"version": "1.4
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "π§ HODL Wallet - Fast CLI crypto wallet!",
|
|
5
5
|
"author": "Martin Clasen",
|
|
6
6
|
"repository": {
|
|
@@ -39,7 +39,11 @@
|
|
|
39
39
|
"evm",
|
|
40
40
|
"polygon",
|
|
41
41
|
"matic",
|
|
42
|
-
"
|
|
42
|
+
"arbitrum",
|
|
43
|
+
"fantom",
|
|
44
|
+
"optimism",
|
|
45
|
+
"avalanche",
|
|
46
|
+
"avax",
|
|
43
47
|
"clasen"
|
|
44
48
|
],
|
|
45
49
|
"dependencies": {
|
|
@@ -53,4 +57,4 @@
|
|
|
53
57
|
"inquirer-fuzzy-path": "^2.3.0",
|
|
54
58
|
"web3": "^4.13.0"
|
|
55
59
|
}
|
|
56
|
-
}
|
|
60
|
+
}
|