fuego-cli 1.0.0 → 1.1.0
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 +83 -2
- package/dist/commands/addbook.d.ts +9 -0
- package/dist/commands/addbook.d.ts.map +1 -0
- package/dist/commands/addbook.js +111 -0
- package/dist/commands/addbook.js.map +1 -0
- package/dist/commands/addrpc.d.ts +7 -0
- package/dist/commands/addrpc.d.ts.map +1 -0
- package/dist/commands/addrpc.js +41 -0
- package/dist/commands/addrpc.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +12 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/send.d.ts +7 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +128 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/addbook.ts +155 -0
- package/src/commands/addrpc.ts +57 -0
- package/src/commands/create.ts +14 -1
- package/src/commands/send.ts +162 -0
- package/src/index.ts +43 -0
- package/fuego-cli-0.1.0.tgz +0 -0
- package/fuego-cli-1.0.0.tgz +0 -0
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
**The first Solana wallet CLI designed FOR autonomous agents.**
|
|
27
27
|
|
|
28
|
-
- ⚡ **
|
|
28
|
+
- ⚡ **Zero friction** — No prompts, no waiting, just instant signing
|
|
29
29
|
- 🤖 **Agent-first** — Built for automated workflows
|
|
30
30
|
- 🏠 **Local-only** — Keys never leave your machine
|
|
31
31
|
- 🔄 **Auto-updating** — Stay current with `fuego update`
|
|
@@ -70,6 +70,9 @@ fuego dashboard
|
|
|
70
70
|
| `fuego create` | Create a new Solana wallet |
|
|
71
71
|
| `fuego address` | Show your wallet address |
|
|
72
72
|
| `fuego balance` | Check SOL, USDC, USDT balances |
|
|
73
|
+
| `fuego addrpc` | Configure your Solana RPC endpoint |
|
|
74
|
+
| `fuego addbook` | Manage your address book |
|
|
75
|
+
| `fuego send` | Send SOL, USDC, or USDT to an address or contact |
|
|
73
76
|
|
|
74
77
|
### Project Management
|
|
75
78
|
|
|
@@ -101,7 +104,9 @@ fuego create --name prod-wallet
|
|
|
101
104
|
~/.fuego/
|
|
102
105
|
├── wallet.json # Private key (600 permissions)
|
|
103
106
|
├── wallet-config.json # Public key + metadata
|
|
104
|
-
|
|
107
|
+
├── config.json # CLI config with versions
|
|
108
|
+
└── contacts/
|
|
109
|
+
└── address-book.json # Your saved contacts
|
|
105
110
|
```
|
|
106
111
|
|
|
107
112
|
---
|
|
@@ -186,6 +191,82 @@ fuego update --fuego
|
|
|
186
191
|
|
|
187
192
|
---
|
|
188
193
|
|
|
194
|
+
### `fuego addrpc [options]`
|
|
195
|
+
|
|
196
|
+
Configure your Solana RPC endpoint for faster or more reliable connections.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Show current RPC configuration
|
|
200
|
+
fuego addrpc
|
|
201
|
+
|
|
202
|
+
# Set a custom RPC endpoint
|
|
203
|
+
fuego addrpc --url https://helius.xyz/... --network mainnet
|
|
204
|
+
|
|
205
|
+
# Use public mainnet
|
|
206
|
+
fuego addrpc --url https://api.mainnet-beta.solana.com
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Options:**
|
|
210
|
+
- `-u, --url <url>` — RPC endpoint URL
|
|
211
|
+
- `-n, --network <network>` — Network type: `mainnet`, `devnet`, `testnet` (default: `mainnet`)
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### `fuego addbook <subcommand>`
|
|
216
|
+
|
|
217
|
+
Manage your address book for quick access to frequently used addresses.
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Add a contact
|
|
221
|
+
fuego addbook add melanie GvCoHGGBR97Yphzc6SrRycZyS31oUYBM8m9hLRtJT7r5 --label "Melanie's wallet"
|
|
222
|
+
|
|
223
|
+
# List all contacts
|
|
224
|
+
fuego addbook list
|
|
225
|
+
|
|
226
|
+
# Show specific contact
|
|
227
|
+
fuego addbook show melanie
|
|
228
|
+
|
|
229
|
+
# Remove contact (with confirmation)
|
|
230
|
+
fuego addbook remove melanie --yes
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Storage:** `~/.fuego/contacts/address-book.json`
|
|
234
|
+
|
|
235
|
+
**Commands:**
|
|
236
|
+
- `add <name> <address> [--label "description"]` — Add a contact
|
|
237
|
+
- `list` — Show all contacts
|
|
238
|
+
- `show <name>` — Show contact details
|
|
239
|
+
- `remove <name> [--yes]` — Remove a contact
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### `fuego send <recipient> <amount>`
|
|
244
|
+
|
|
245
|
+
Send SOL, USDC, or USDT to a Solana address or address book contact.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Send SOL to an address
|
|
249
|
+
fuego send GvCoHGGBR97Yphzc6SrRycZyS31oUYBM8m9hLRtJT7r5 0.5 --token SOL
|
|
250
|
+
|
|
251
|
+
# Send USDC to an address book contact
|
|
252
|
+
fuego send melanie 10 --token USDC
|
|
253
|
+
|
|
254
|
+
# Send and confirm immediately
|
|
255
|
+
fuego send melanie 5 --token USDT --yes
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Options:**
|
|
259
|
+
- `-t, --token <token>` — **Required.** Token to send: `SOL`, `USDC`, or `USDT`
|
|
260
|
+
- `-y, --yes` — Skip confirmation prompt and send immediately
|
|
261
|
+
|
|
262
|
+
**Recipient can be:**
|
|
263
|
+
- A full Solana address (e.g., `GvCoHGGBR97Yphzc6SrRycZyS31oUYBM8m9hLRtJT7r5`)
|
|
264
|
+
- An address book contact name (e.g., `melanie`)
|
|
265
|
+
|
|
266
|
+
**Safety:** By default, `fuego send` shows a transaction preview and requires `--yes` to confirm. This prevents accidental sends.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
189
270
|
### `fuego install [options]`
|
|
190
271
|
|
|
191
272
|
Install the [Fuego project](https://github.com/willmcdeezy/fuego) — Rust server, Python scripts, and dashboard.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function addBookAddCommand(name: string, address: string, options: {
|
|
2
|
+
label?: string;
|
|
3
|
+
}): Promise<void>;
|
|
4
|
+
export declare function addBookListCommand(): Promise<void>;
|
|
5
|
+
export declare function addBookShowCommand(name: string): Promise<void>;
|
|
6
|
+
export declare function addBookRemoveCommand(name: string, options: {
|
|
7
|
+
yes?: boolean;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=addbook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addbook.d.ts","sourceRoot":"","sources":["../../src/commands/addbook.ts"],"names":[],"mappings":"AAqCA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCjH;AAGD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqBxD;AAGD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBpE;AAGD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BlG"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { showSuccess, showInfo, showWarning, flameDivider } from '../lib/ascii.js';
|
|
6
|
+
const CONTACTS_DIR = path.join(os.homedir(), '.fuego', 'contacts');
|
|
7
|
+
const ADDRESS_BOOK_FILE = path.join(CONTACTS_DIR, 'address-book.json');
|
|
8
|
+
function loadAddressBook() {
|
|
9
|
+
if (!fs.existsSync(ADDRESS_BOOK_FILE)) {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
return fs.readJsonSync(ADDRESS_BOOK_FILE);
|
|
13
|
+
}
|
|
14
|
+
function saveAddressBook(book) {
|
|
15
|
+
fs.ensureDirSync(CONTACTS_DIR);
|
|
16
|
+
fs.writeJsonSync(ADDRESS_BOOK_FILE, book, { spaces: 2 });
|
|
17
|
+
}
|
|
18
|
+
function isValidSolanaAddress(address) {
|
|
19
|
+
// Basic Solana address validation (32-44 chars, base58)
|
|
20
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
21
|
+
}
|
|
22
|
+
// Add a contact
|
|
23
|
+
export async function addBookAddCommand(name, address, options) {
|
|
24
|
+
console.log();
|
|
25
|
+
if (!name || !address) {
|
|
26
|
+
console.log(chalk.red('❌ Usage: fuego addbook add <name> <address> [--label "description"]'));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// Validate address
|
|
30
|
+
if (!isValidSolanaAddress(address)) {
|
|
31
|
+
console.log(chalk.red('❌ Invalid Solana address format.'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const book = loadAddressBook();
|
|
35
|
+
// Check if name already exists
|
|
36
|
+
if (book[name]) {
|
|
37
|
+
showWarning(`Contact "${name}" already exists.\n\nUse a different name or remove the existing contact first.`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Add contact
|
|
41
|
+
book[name] = {
|
|
42
|
+
address,
|
|
43
|
+
label: options.label,
|
|
44
|
+
addedAt: new Date().toISOString()
|
|
45
|
+
};
|
|
46
|
+
saveAddressBook(book);
|
|
47
|
+
showSuccess('✅ Contact Added', `Name: ${chalk.cyan(name)}\nAddress: ${chalk.cyan(address.slice(0, 8))}...${chalk.cyan(address.slice(-8))}${options.label ? '\nLabel: ' + chalk.cyan(options.label) : ''}`);
|
|
48
|
+
flameDivider();
|
|
49
|
+
}
|
|
50
|
+
// List all contacts
|
|
51
|
+
export async function addBookListCommand() {
|
|
52
|
+
console.log();
|
|
53
|
+
const book = loadAddressBook();
|
|
54
|
+
const contacts = Object.entries(book);
|
|
55
|
+
if (contacts.length === 0) {
|
|
56
|
+
showInfo('📒 Address Book', ['No contacts yet.', '', chalk.yellow('Add one: fuego addbook add <name> <address>')]);
|
|
57
|
+
flameDivider();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const lines = [`${contacts.length} contact${contacts.length === 1 ? '' : 's'}\n`];
|
|
61
|
+
for (const [name, entry] of contacts) {
|
|
62
|
+
const shortAddr = `${entry.address.slice(0, 6)}...${entry.address.slice(-6)}`;
|
|
63
|
+
lines.push(`${chalk.cyan(name)}: ${chalk.white(shortAddr)}${entry.label ? chalk.gray(` (${entry.label})`) : ''}`);
|
|
64
|
+
}
|
|
65
|
+
showInfo('📒 Address Book', lines);
|
|
66
|
+
flameDivider();
|
|
67
|
+
}
|
|
68
|
+
// Show a specific contact
|
|
69
|
+
export async function addBookShowCommand(name) {
|
|
70
|
+
console.log();
|
|
71
|
+
if (!name) {
|
|
72
|
+
console.log(chalk.red('❌ Usage: fuego addbook show <name>'));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
const book = loadAddressBook();
|
|
76
|
+
const entry = book[name];
|
|
77
|
+
if (!entry) {
|
|
78
|
+
console.log(chalk.red(`❌ Contact "${name}" not found.`));
|
|
79
|
+
console.log(chalk.gray('\nUse "fuego addbook list" to see all contacts.'));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
showInfo(`📇 ${name}`, [
|
|
83
|
+
`Address: ${chalk.white(entry.address)}`,
|
|
84
|
+
entry.label ? `Label: ${chalk.cyan(entry.label)}` : '',
|
|
85
|
+
`Added: ${chalk.gray(new Date(entry.addedAt).toLocaleDateString())}`
|
|
86
|
+
].filter(Boolean));
|
|
87
|
+
flameDivider();
|
|
88
|
+
}
|
|
89
|
+
// Remove a contact
|
|
90
|
+
export async function addBookRemoveCommand(name, options) {
|
|
91
|
+
console.log();
|
|
92
|
+
if (!name) {
|
|
93
|
+
console.log(chalk.red('❌ Usage: fuego addbook remove <name> [--yes]'));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const book = loadAddressBook();
|
|
97
|
+
if (!book[name]) {
|
|
98
|
+
console.log(chalk.red(`❌ Contact "${name}" not found.`));
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
// Confirm unless --yes flag
|
|
102
|
+
if (!options.yes) {
|
|
103
|
+
showWarning(`About to remove "${name}" (${book[name].address.slice(0, 8)}...${book[name].address.slice(-8)})\n\nUse --yes to confirm, or omit to review.`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
delete book[name];
|
|
107
|
+
saveAddressBook(book);
|
|
108
|
+
showSuccess('✅ Contact Removed', `Removed "${chalk.cyan(name)}" from address book.`);
|
|
109
|
+
flameDivider();
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=addbook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addbook.js","sourceRoot":"","sources":["../../src/commands/addbook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addrpc.d.ts","sourceRoot":"","sources":["../../src/commands/addrpc.ts"],"names":[],"mappings":"AAIA,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CzE"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { setConfig, getConfig } from '../lib/config.js';
|
|
3
|
+
import { showSuccess, showInfo, flameDivider } from '../lib/ascii.js';
|
|
4
|
+
export async function addRpcCommand(options) {
|
|
5
|
+
console.log(); // spacer
|
|
6
|
+
// If no URL provided, show current config and help
|
|
7
|
+
if (!options.url) {
|
|
8
|
+
const currentRpc = getConfig('rpcUrl');
|
|
9
|
+
const currentNetwork = getConfig('network');
|
|
10
|
+
showInfo('⚙️ Current RPC Configuration', [
|
|
11
|
+
`RPC URL: ${currentRpc ? chalk.cyan(currentRpc) : chalk.gray('Not set')}`,
|
|
12
|
+
`Network: ${currentNetwork ? chalk.cyan(currentNetwork) : chalk.gray('mainnet')}`,
|
|
13
|
+
'',
|
|
14
|
+
`${chalk.yellow('Usage:')} fuego addrpc --url https://api.mainnet-beta.solana.com`,
|
|
15
|
+
`${chalk.yellow('Or:')} fuego addrpc --url https://helius.xyz/... --network mainnet`
|
|
16
|
+
]);
|
|
17
|
+
flameDivider();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Validate URL
|
|
21
|
+
try {
|
|
22
|
+
new URL(options.url);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
console.log(chalk.red('❌ Invalid URL. Please provide a valid RPC endpoint.'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
// Set the RPC URL
|
|
29
|
+
setConfig('rpcUrl', options.url);
|
|
30
|
+
// Set network if provided, default to mainnet
|
|
31
|
+
const network = options.network || 'mainnet';
|
|
32
|
+
setConfig('network', network);
|
|
33
|
+
showSuccess('✅ RPC Configuration Updated', `URL: ${chalk.cyan(options.url)}\nNetwork: ${chalk.cyan(network)}`);
|
|
34
|
+
showInfo('💡 Tips', [
|
|
35
|
+
'Premium RPCs (Helius, QuickNode) offer better performance',
|
|
36
|
+
'Free public RPCs may have rate limits',
|
|
37
|
+
'Your wallet address remains the same across networks'
|
|
38
|
+
]);
|
|
39
|
+
flameDivider();
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=addrpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addrpc.js","sourceRoot":"","sources":["../../src/commands/addrpc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAc,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAOtE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,SAAS;IAExB,mDAAmD;IACnD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACjB,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,cAAc,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAE5C,QAAQ,CAAC,+BAA+B,EAAE;YACxC,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;YACzE,YAAY,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;YACjF,EAAE;YACF,GAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,yDAAyD;YAClF,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,kEAAkE;SACzF,CAAC,CAAC;QAEH,YAAY,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IAED,eAAe;IACf,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAEjC,8CAA8C;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;IAC7C,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE9B,WAAW,CACT,6BAA6B,EAC7B,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CACnE,CAAC;IAEF,QAAQ,CAAC,SAAS,EAAE;QAClB,2DAA2D;QAC3D,uCAAuC;QACvC,sDAAsD;KACvD,CAAC,CAAC;IAEH,YAAY,EAAE,CAAC;AACjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAQA,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuFzE"}
|
package/dist/commands/create.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
import { FuegoWallet } from '../lib/wallet.js';
|
|
4
5
|
import { getWalletPath, getConfigPath, getFuegoCliVersion, setFuegoCliVersion } from '../lib/config.js';
|
|
5
6
|
import { showSuccess, showWarning, showInfo, formatPublicKey, flameDivider } from '../lib/ascii.js';
|
|
@@ -38,6 +39,15 @@ export async function createCommand(options) {
|
|
|
38
39
|
network: existingConfig.network || 'mainnet',
|
|
39
40
|
rpcUrl: existingConfig.rpcUrl || 'https://api.mainnet-beta.solana.com'
|
|
40
41
|
}, { spaces: 2 });
|
|
42
|
+
// Create address book directory and empty file
|
|
43
|
+
const contactsDir = options.directory
|
|
44
|
+
? `${options.directory}/contacts`
|
|
45
|
+
: path.join(path.dirname(getConfigPath()), 'contacts');
|
|
46
|
+
const addressBookPath = path.join(contactsDir, 'address-book.json');
|
|
47
|
+
if (!fs.existsSync(addressBookPath)) {
|
|
48
|
+
fs.ensureDirSync(contactsDir);
|
|
49
|
+
fs.writeJsonSync(addressBookPath, {}, { spaces: 2 });
|
|
50
|
+
}
|
|
41
51
|
// Store fuego-cli version
|
|
42
52
|
setFuegoCliVersion(getFuegoCliVersion());
|
|
43
53
|
spinner.stop();
|
|
@@ -51,7 +61,8 @@ export async function createCommand(options) {
|
|
|
51
61
|
// File locations
|
|
52
62
|
showInfo('📁 Wallet Files', [
|
|
53
63
|
'Keypair: ~/.fuego/wallet.json',
|
|
54
|
-
'Config: ~/.fuego/wallet-config.json'
|
|
64
|
+
'Config: ~/.fuego/wallet-config.json',
|
|
65
|
+
'Contacts: ~/.fuego/contacts/address-book.json'
|
|
55
66
|
]);
|
|
56
67
|
flameDivider();
|
|
57
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACxG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpG,OAAO,EAAE,MAAM,UAAU,CAAC;AAQ1B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,SAAS;IAExB,MAAM,OAAO,GAAG,GAAG,CAAC;QAClB,IAAI,EAAE,iCAAiC;QACvC,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEX,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS;YAClC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,cAAc;YACpC,CAAC,CAAC,aAAa,EAAE,CAAC;QAEpB,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC;QAE3C,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACtC,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,WAAW,CAAC,iHAAiH,CAAC,CAAC;YAC/H,OAAO;QACT,CAAC;QAED,OAAO,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAClD,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QAEtB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAElE,+BAA+B;QAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS;YAClC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,cAAc;YACpC,CAAC,CAAC,aAAa,EAAE,CAAC;QAEpB,2DAA2D;QAC3D,IAAI,cAAc,GAAQ,EAAE,CAAC;QAC7B,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAC/C,CAAC;QAED,qDAAqD;QACrD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE;YAC3B,GAAG,cAAc;YACjB,OAAO,EAAE,cAAc,CAAC,OAAO,IAAI,SAAS;YAC5C,MAAM,EAAE,cAAc,CAAC,MAAM,IAAI,qCAAqC;SACvE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAElB,0BAA0B;QAC1B,kBAAkB,CAAC,kBAAkB,EAAE,CAAC,CAAC;QAEzC,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,kBAAkB;QAClB,WAAW,CACT,iCAAiC,EACjC,SAAS,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC,iBAAiB,eAAe,CAAC,SAAS,CAAC,EAAE,CAC5F,CAAC;QAEF,IAAI,QAAQ,EAAE,CAAC;YACb,WAAW,CACT,yCAAyC;gBACzC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACrB,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAC3D,CAAC;QACJ,CAAC;QAED,iBAAiB;QACjB,QAAQ,CAAC,iBAAiB,EAAE;YAC1B,+BAA+B;YAC/B,qCAAqC;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAUA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAiCD,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAmHxG"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { loadWalletConfig, findFuegoPath } from '../lib/config.js';
|
|
6
|
+
import { showSuccess, showInfo, showError, formatPublicKey, flameDivider } from '../lib/ascii.js';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
const ADDRESS_BOOK_FILE = path.join(os.homedir(), '.fuego', 'contacts', 'address-book.json');
|
|
9
|
+
function loadAddressBook() {
|
|
10
|
+
if (!fs.existsSync(ADDRESS_BOOK_FILE)) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
return fs.readJsonSync(ADDRESS_BOOK_FILE);
|
|
14
|
+
}
|
|
15
|
+
function resolveRecipient(recipient) {
|
|
16
|
+
// Check if it's a direct address (32-44 chars, base58)
|
|
17
|
+
if (/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(recipient)) {
|
|
18
|
+
return recipient;
|
|
19
|
+
}
|
|
20
|
+
// Check address book
|
|
21
|
+
const book = loadAddressBook();
|
|
22
|
+
if (book[recipient]) {
|
|
23
|
+
return book[recipient].address;
|
|
24
|
+
}
|
|
25
|
+
// Not found
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
export async function sendCommand(recipient, amount, options) {
|
|
29
|
+
console.log();
|
|
30
|
+
// Validate inputs
|
|
31
|
+
if (!recipient || !amount) {
|
|
32
|
+
console.log(chalk.red('❌ Usage: fuego send <recipient> <amount> --token SOL|USDC|USDT [--yes]'));
|
|
33
|
+
console.log(chalk.gray('\nExamples:'));
|
|
34
|
+
console.log(chalk.gray(' fuego send GvCo... 0.5 --token SOL'));
|
|
35
|
+
console.log(chalk.gray(' fuego send melanie 10 --token USDC'));
|
|
36
|
+
console.log(chalk.gray(' fuego send melanie 5 --token USDT --yes'));
|
|
37
|
+
console.log(chalk.gray('\nRecipient can be an address or address book contact name.'));
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
// Load wallet
|
|
41
|
+
const walletConfig = loadWalletConfig();
|
|
42
|
+
if (!walletConfig) {
|
|
43
|
+
console.log(chalk.red('❌ No wallet found. Run "fuego create" first.'));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
// Resolve recipient
|
|
47
|
+
const resolvedAddress = resolveRecipient(recipient);
|
|
48
|
+
if (!resolvedAddress) {
|
|
49
|
+
console.log(chalk.red(`❌ Recipient "${recipient}" not found.`));
|
|
50
|
+
console.log(chalk.gray('\nCheck your address book: fuego addbook list'));
|
|
51
|
+
console.log(chalk.gray('Or use a full Solana address.'));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
// Validate amount
|
|
55
|
+
const amountNum = parseFloat(amount);
|
|
56
|
+
if (isNaN(amountNum) || amountNum <= 0) {
|
|
57
|
+
console.log(chalk.red('❌ Invalid amount. Please provide a positive number.'));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
// Determine token
|
|
61
|
+
const token = (options.token || '').toUpperCase();
|
|
62
|
+
if (!token) {
|
|
63
|
+
console.log(chalk.red('❌ Token is required. Use: --token SOL, --token USDC, or --token USDT'));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
if (!['SOL', 'USDC', 'USDT'].includes(token)) {
|
|
67
|
+
console.log(chalk.red('❌ Invalid token. Use: SOL, USDC, or USDT'));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
// Show transaction details
|
|
71
|
+
const isContact = recipient !== resolvedAddress;
|
|
72
|
+
showInfo('📝 Transaction Preview', [
|
|
73
|
+
`From: ${chalk.cyan(formatPublicKey(walletConfig.publicKey))}`,
|
|
74
|
+
`To: ${chalk.cyan(formatPublicKey(resolvedAddress))}${isContact ? chalk.gray(` (${recipient})`) : ''}`,
|
|
75
|
+
`Amount: ${chalk.yellow(amount)} ${chalk.cyan(token)}`,
|
|
76
|
+
`Network: ${chalk.gray('mainnet-beta')}`
|
|
77
|
+
]);
|
|
78
|
+
// Confirm unless --yes
|
|
79
|
+
if (!options.yes) {
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(chalk.yellow('⚠️ Add --yes to confirm and send'));
|
|
82
|
+
flameDivider();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.log();
|
|
86
|
+
console.log(chalk.blue('⏳ Executing transaction via Fuego...'));
|
|
87
|
+
// Find fuego installation path and call Python script
|
|
88
|
+
const fuegoPath = findFuegoPath();
|
|
89
|
+
if (!fuegoPath) {
|
|
90
|
+
showError('Fuego installation not found. Run "fuego install" first.');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
const scriptPath = path.join(fuegoPath, 'scripts', 'fuego_transfer.py');
|
|
94
|
+
const pythonProcess = spawn('python3', [
|
|
95
|
+
scriptPath,
|
|
96
|
+
'--from', walletConfig.publicKey,
|
|
97
|
+
'--to', resolvedAddress,
|
|
98
|
+
'--amount', amount,
|
|
99
|
+
'--token', token
|
|
100
|
+
]);
|
|
101
|
+
let output = '';
|
|
102
|
+
let errorOutput = '';
|
|
103
|
+
pythonProcess.stdout.on('data', (data) => {
|
|
104
|
+
output += data.toString();
|
|
105
|
+
process.stdout.write(data);
|
|
106
|
+
});
|
|
107
|
+
pythonProcess.stderr.on('data', (data) => {
|
|
108
|
+
errorOutput += data.toString();
|
|
109
|
+
});
|
|
110
|
+
pythonProcess.on('close', (code) => {
|
|
111
|
+
if (code === 0) {
|
|
112
|
+
// Extract signature from output if present
|
|
113
|
+
const sigMatch = output.match(/Signature: ([A-Za-z0-9]+)/);
|
|
114
|
+
if (sigMatch) {
|
|
115
|
+
showSuccess('✅ Transaction Sent!', `Amount: ${chalk.yellow(amount)} ${chalk.cyan(token)}\nTo: ${chalk.cyan(isContact ? recipient : formatPublicKey(resolvedAddress))}`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
showSuccess('✅ Transaction Complete!', '');
|
|
119
|
+
}
|
|
120
|
+
flameDivider();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
showError(`Transaction failed: ${errorOutput || 'Unknown error'}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=send.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/commands/send.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAClG,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;AAe7F,SAAS,eAAe;IACtB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IACzC,uDAAuD;IACvD,IAAI,+BAA+B,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,qBAAqB;IACrB,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;IACjC,CAAC;IAED,YAAY;IACZ,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAiB,EAAE,MAAc,EAAE,OAAoB;IACvF,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,kBAAkB;IAClB,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,wEAAwE,CAAC,CAAC,CAAC;QACjG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,cAAc;IACd,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;IACxC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,oBAAoB;IACpB,MAAM,eAAe,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,SAAS,cAAc,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC,CAAC;QAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,2BAA2B;IAC3B,MAAM,SAAS,GAAG,SAAS,KAAK,eAAe,CAAC;IAChD,QAAQ,CAAC,wBAAwB,EAAE;QACjC,SAAS,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE;QAC9D,OAAO,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QACtG,WAAW,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QACtD,YAAY,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;KACzC,CAAC,CAAC;IAEH,uBAAuB;IACvB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC/D,YAAY,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC,CAAC;IAEhE,sDAAsD;IACtD,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,CAAC,0DAA0D,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAExE,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,EAAE;QACrC,UAAU;QACV,QAAQ,EAAE,YAAY,CAAC,SAAS;QAChC,MAAM,EAAE,eAAe;QACvB,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IAEH,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,WAAW,GAAG,EAAE,CAAC;IAErB,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACvC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACvC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QACjC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;YACf,2CAA2C;YAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC3D,IAAI,QAAQ,EAAE,CAAC;gBACb,WAAW,CACT,qBAAqB,EACrB,WAAW,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,EAAE,CACpI,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,YAAY,EAAE,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,uBAAuB,WAAW,IAAI,eAAe,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,9 @@ import { balanceCommand } from './commands/balance.js';
|
|
|
8
8
|
import { serveCommand } from './commands/serve.js';
|
|
9
9
|
import { dashboardCommand } from './commands/dashboard.js';
|
|
10
10
|
import { updateCommand } from './commands/update.js';
|
|
11
|
+
import { addRpcCommand } from './commands/addrpc.js';
|
|
12
|
+
import { addBookAddCommand, addBookListCommand, addBookShowCommand, addBookRemoveCommand } from './commands/addbook.js';
|
|
13
|
+
import { sendCommand } from './commands/send.js';
|
|
11
14
|
import { showBanner } from './lib/ascii.js';
|
|
12
15
|
async function main() {
|
|
13
16
|
// Show banner for help and when no args provided
|
|
@@ -60,6 +63,39 @@ async function main() {
|
|
|
60
63
|
.option('--cli', 'Update only fuego-cli')
|
|
61
64
|
.option('--fuego', 'Update only the fuego project')
|
|
62
65
|
.action(updateCommand);
|
|
66
|
+
program
|
|
67
|
+
.command('addrpc')
|
|
68
|
+
.description('Add or update your Solana RPC endpoint')
|
|
69
|
+
.option('-u, --url <url>', 'RPC endpoint URL (e.g., https://api.mainnet-beta.solana.com)')
|
|
70
|
+
.option('-n, --network <network>', 'Network type (mainnet, devnet, testnet)', 'mainnet')
|
|
71
|
+
.action(addRpcCommand);
|
|
72
|
+
const addbook = program
|
|
73
|
+
.command('addbook')
|
|
74
|
+
.description('Manage your address book (stored in ~/.fuego/contacts/address-book.json)');
|
|
75
|
+
addbook
|
|
76
|
+
.command('add <name> <address>')
|
|
77
|
+
.description('Add a contact to your address book')
|
|
78
|
+
.option('-l, --label <label>', 'Optional description/label for this contact')
|
|
79
|
+
.action(addBookAddCommand);
|
|
80
|
+
addbook
|
|
81
|
+
.command('list')
|
|
82
|
+
.description('List all contacts in your address book')
|
|
83
|
+
.action(addBookListCommand);
|
|
84
|
+
addbook
|
|
85
|
+
.command('show <name>')
|
|
86
|
+
.description('Show details for a specific contact')
|
|
87
|
+
.action(addBookShowCommand);
|
|
88
|
+
addbook
|
|
89
|
+
.command('remove <name>')
|
|
90
|
+
.description('Remove a contact from your address book')
|
|
91
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
92
|
+
.action(addBookRemoveCommand);
|
|
93
|
+
program
|
|
94
|
+
.command('send <recipient> <amount>')
|
|
95
|
+
.description('Send SOL, USDC, or USDT to an address or contact')
|
|
96
|
+
.requiredOption('-t, --token <token>', 'Token to send (SOL, USDC, USDT)')
|
|
97
|
+
.option('-y, --yes', 'Skip confirmation and send immediately')
|
|
98
|
+
.action(sendCommand);
|
|
63
99
|
await program.parseAsync(process.argv);
|
|
64
100
|
}
|
|
65
101
|
main().catch((error) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { showSuccess, showInfo, showWarning, flameDivider } from '../lib/ascii.js';
|
|
6
|
+
|
|
7
|
+
const CONTACTS_DIR = path.join(os.homedir(), '.fuego', 'contacts');
|
|
8
|
+
const ADDRESS_BOOK_FILE = path.join(CONTACTS_DIR, 'address-book.json');
|
|
9
|
+
|
|
10
|
+
interface ContactEntry {
|
|
11
|
+
address: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
addedAt: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface AddressBook {
|
|
17
|
+
[name: string]: ContactEntry;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function loadAddressBook(): AddressBook {
|
|
21
|
+
if (!fs.existsSync(ADDRESS_BOOK_FILE)) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
return fs.readJsonSync(ADDRESS_BOOK_FILE);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function saveAddressBook(book: AddressBook): void {
|
|
28
|
+
fs.ensureDirSync(CONTACTS_DIR);
|
|
29
|
+
fs.writeJsonSync(ADDRESS_BOOK_FILE, book, { spaces: 2 });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isValidSolanaAddress(address: string): boolean {
|
|
33
|
+
// Basic Solana address validation (32-44 chars, base58)
|
|
34
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add a contact
|
|
38
|
+
export async function addBookAddCommand(name: string, address: string, options: { label?: string }): Promise<void> {
|
|
39
|
+
console.log();
|
|
40
|
+
|
|
41
|
+
if (!name || !address) {
|
|
42
|
+
console.log(chalk.red('❌ Usage: fuego addbook add <name> <address> [--label "description"]'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Validate address
|
|
47
|
+
if (!isValidSolanaAddress(address)) {
|
|
48
|
+
console.log(chalk.red('❌ Invalid Solana address format.'));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const book = loadAddressBook();
|
|
53
|
+
|
|
54
|
+
// Check if name already exists
|
|
55
|
+
if (book[name]) {
|
|
56
|
+
showWarning(`Contact "${name}" already exists.\n\nUse a different name or remove the existing contact first.`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Add contact
|
|
61
|
+
book[name] = {
|
|
62
|
+
address,
|
|
63
|
+
label: options.label,
|
|
64
|
+
addedAt: new Date().toISOString()
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
saveAddressBook(book);
|
|
68
|
+
|
|
69
|
+
showSuccess(
|
|
70
|
+
'✅ Contact Added',
|
|
71
|
+
`Name: ${chalk.cyan(name)}\nAddress: ${chalk.cyan(address.slice(0, 8))}...${chalk.cyan(address.slice(-8))}${options.label ? '\nLabel: ' + chalk.cyan(options.label) : ''}`
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
flameDivider();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// List all contacts
|
|
78
|
+
export async function addBookListCommand(): Promise<void> {
|
|
79
|
+
console.log();
|
|
80
|
+
|
|
81
|
+
const book = loadAddressBook();
|
|
82
|
+
const contacts = Object.entries(book);
|
|
83
|
+
|
|
84
|
+
if (contacts.length === 0) {
|
|
85
|
+
showInfo('📒 Address Book', ['No contacts yet.', '', chalk.yellow('Add one: fuego addbook add <name> <address>')]);
|
|
86
|
+
flameDivider();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const lines: string[] = [`${contacts.length} contact${contacts.length === 1 ? '' : 's'}\n`];
|
|
91
|
+
|
|
92
|
+
for (const [name, entry] of contacts) {
|
|
93
|
+
const shortAddr = `${entry.address.slice(0, 6)}...${entry.address.slice(-6)}`;
|
|
94
|
+
lines.push(`${chalk.cyan(name)}: ${chalk.white(shortAddr)}${entry.label ? chalk.gray(` (${entry.label})`) : ''}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
showInfo('📒 Address Book', lines);
|
|
98
|
+
flameDivider();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Show a specific contact
|
|
102
|
+
export async function addBookShowCommand(name: string): Promise<void> {
|
|
103
|
+
console.log();
|
|
104
|
+
|
|
105
|
+
if (!name) {
|
|
106
|
+
console.log(chalk.red('❌ Usage: fuego addbook show <name>'));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const book = loadAddressBook();
|
|
111
|
+
const entry = book[name];
|
|
112
|
+
|
|
113
|
+
if (!entry) {
|
|
114
|
+
console.log(chalk.red(`❌ Contact "${name}" not found.`));
|
|
115
|
+
console.log(chalk.gray('\nUse "fuego addbook list" to see all contacts.'));
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
showInfo(`📇 ${name}`, [
|
|
120
|
+
`Address: ${chalk.white(entry.address)}`,
|
|
121
|
+
entry.label ? `Label: ${chalk.cyan(entry.label)}` : '',
|
|
122
|
+
`Added: ${chalk.gray(new Date(entry.addedAt).toLocaleDateString())}`
|
|
123
|
+
].filter(Boolean));
|
|
124
|
+
|
|
125
|
+
flameDivider();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Remove a contact
|
|
129
|
+
export async function addBookRemoveCommand(name: string, options: { yes?: boolean }): Promise<void> {
|
|
130
|
+
console.log();
|
|
131
|
+
|
|
132
|
+
if (!name) {
|
|
133
|
+
console.log(chalk.red('❌ Usage: fuego addbook remove <name> [--yes]'));
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const book = loadAddressBook();
|
|
138
|
+
|
|
139
|
+
if (!book[name]) {
|
|
140
|
+
console.log(chalk.red(`❌ Contact "${name}" not found.`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Confirm unless --yes flag
|
|
145
|
+
if (!options.yes) {
|
|
146
|
+
showWarning(`About to remove "${name}" (${book[name].address.slice(0, 8)}...${book[name].address.slice(-8)})\n\nUse --yes to confirm, or omit to review.`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
delete book[name];
|
|
151
|
+
saveAddressBook(book);
|
|
152
|
+
|
|
153
|
+
showSuccess('✅ Contact Removed', `Removed "${chalk.cyan(name)}" from address book.`);
|
|
154
|
+
flameDivider();
|
|
155
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { setConfig, getConfig, listConfig } from '../lib/config.js';
|
|
3
|
+
import { showSuccess, showInfo, flameDivider } from '../lib/ascii.js';
|
|
4
|
+
|
|
5
|
+
interface AddRpcOptions {
|
|
6
|
+
url?: string;
|
|
7
|
+
network?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function addRpcCommand(options: AddRpcOptions): Promise<void> {
|
|
11
|
+
console.log(); // spacer
|
|
12
|
+
|
|
13
|
+
// If no URL provided, show current config and help
|
|
14
|
+
if (!options.url) {
|
|
15
|
+
const currentRpc = getConfig('rpcUrl');
|
|
16
|
+
const currentNetwork = getConfig('network');
|
|
17
|
+
|
|
18
|
+
showInfo('⚙️ Current RPC Configuration', [
|
|
19
|
+
`RPC URL: ${currentRpc ? chalk.cyan(currentRpc) : chalk.gray('Not set')}`,
|
|
20
|
+
`Network: ${currentNetwork ? chalk.cyan(currentNetwork) : chalk.gray('mainnet')}`,
|
|
21
|
+
'',
|
|
22
|
+
`${chalk.yellow('Usage:')} fuego addrpc --url https://api.mainnet-beta.solana.com`,
|
|
23
|
+
`${chalk.yellow('Or:')} fuego addrpc --url https://helius.xyz/... --network mainnet`
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
flameDivider();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Validate URL
|
|
31
|
+
try {
|
|
32
|
+
new URL(options.url);
|
|
33
|
+
} catch {
|
|
34
|
+
console.log(chalk.red('❌ Invalid URL. Please provide a valid RPC endpoint.'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Set the RPC URL
|
|
39
|
+
setConfig('rpcUrl', options.url);
|
|
40
|
+
|
|
41
|
+
// Set network if provided, default to mainnet
|
|
42
|
+
const network = options.network || 'mainnet';
|
|
43
|
+
setConfig('network', network);
|
|
44
|
+
|
|
45
|
+
showSuccess(
|
|
46
|
+
'✅ RPC Configuration Updated',
|
|
47
|
+
`URL: ${chalk.cyan(options.url)}\nNetwork: ${chalk.cyan(network)}`
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
showInfo('💡 Tips', [
|
|
51
|
+
'Premium RPCs (Helius, QuickNode) offer better performance',
|
|
52
|
+
'Free public RPCs may have rate limits',
|
|
53
|
+
'Your wallet address remains the same across networks'
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
flameDivider();
|
|
57
|
+
}
|
package/src/commands/create.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
import { FuegoWallet } from '../lib/wallet.js';
|
|
4
5
|
import { getWalletPath, getConfigPath, getFuegoCliVersion, setFuegoCliVersion } from '../lib/config.js';
|
|
5
6
|
import { showSuccess, showWarning, showInfo, formatPublicKey, flameDivider } from '../lib/ascii.js';
|
|
@@ -55,6 +56,17 @@ export async function createCommand(options: CreateOptions): Promise<void> {
|
|
|
55
56
|
rpcUrl: existingConfig.rpcUrl || 'https://api.mainnet-beta.solana.com'
|
|
56
57
|
}, { spaces: 2 });
|
|
57
58
|
|
|
59
|
+
// Create address book directory and empty file
|
|
60
|
+
const contactsDir = options.directory
|
|
61
|
+
? `${options.directory}/contacts`
|
|
62
|
+
: path.join(path.dirname(getConfigPath()), 'contacts');
|
|
63
|
+
const addressBookPath = path.join(contactsDir, 'address-book.json');
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(addressBookPath)) {
|
|
66
|
+
fs.ensureDirSync(contactsDir);
|
|
67
|
+
fs.writeJsonSync(addressBookPath, {}, { spaces: 2 });
|
|
68
|
+
}
|
|
69
|
+
|
|
58
70
|
// Store fuego-cli version
|
|
59
71
|
setFuegoCliVersion(getFuegoCliVersion());
|
|
60
72
|
|
|
@@ -77,7 +89,8 @@ export async function createCommand(options: CreateOptions): Promise<void> {
|
|
|
77
89
|
// File locations
|
|
78
90
|
showInfo('📁 Wallet Files', [
|
|
79
91
|
'Keypair: ~/.fuego/wallet.json',
|
|
80
|
-
'Config: ~/.fuego/wallet-config.json'
|
|
92
|
+
'Config: ~/.fuego/wallet-config.json',
|
|
93
|
+
'Contacts: ~/.fuego/contacts/address-book.json'
|
|
81
94
|
]);
|
|
82
95
|
|
|
83
96
|
flameDivider();
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { loadWalletConfig, findFuegoPath } from '../lib/config.js';
|
|
6
|
+
import { showSuccess, showInfo, showError, formatPublicKey, flameDivider } from '../lib/ascii.js';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
|
|
9
|
+
const ADDRESS_BOOK_FILE = path.join(os.homedir(), '.fuego', 'contacts', 'address-book.json');
|
|
10
|
+
|
|
11
|
+
interface SendOptions {
|
|
12
|
+
token?: string;
|
|
13
|
+
yes?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface AddressBook {
|
|
17
|
+
[name: string]: {
|
|
18
|
+
address: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
addedAt: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function loadAddressBook(): AddressBook {
|
|
25
|
+
if (!fs.existsSync(ADDRESS_BOOK_FILE)) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
return fs.readJsonSync(ADDRESS_BOOK_FILE);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveRecipient(recipient: string): string {
|
|
32
|
+
// Check if it's a direct address (32-44 chars, base58)
|
|
33
|
+
if (/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(recipient)) {
|
|
34
|
+
return recipient;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check address book
|
|
38
|
+
const book = loadAddressBook();
|
|
39
|
+
if (book[recipient]) {
|
|
40
|
+
return book[recipient].address;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Not found
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function sendCommand(recipient: string, amount: string, options: SendOptions): Promise<void> {
|
|
48
|
+
console.log();
|
|
49
|
+
|
|
50
|
+
// Validate inputs
|
|
51
|
+
if (!recipient || !amount) {
|
|
52
|
+
console.log(chalk.red('❌ Usage: fuego send <recipient> <amount> --token SOL|USDC|USDT [--yes]'));
|
|
53
|
+
console.log(chalk.gray('\nExamples:'));
|
|
54
|
+
console.log(chalk.gray(' fuego send GvCo... 0.5 --token SOL'));
|
|
55
|
+
console.log(chalk.gray(' fuego send melanie 10 --token USDC'));
|
|
56
|
+
console.log(chalk.gray(' fuego send melanie 5 --token USDT --yes'));
|
|
57
|
+
console.log(chalk.gray('\nRecipient can be an address or address book contact name.'));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Load wallet
|
|
62
|
+
const walletConfig = loadWalletConfig();
|
|
63
|
+
if (!walletConfig) {
|
|
64
|
+
console.log(chalk.red('❌ No wallet found. Run "fuego create" first.'));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Resolve recipient
|
|
69
|
+
const resolvedAddress = resolveRecipient(recipient);
|
|
70
|
+
if (!resolvedAddress) {
|
|
71
|
+
console.log(chalk.red(`❌ Recipient "${recipient}" not found.`));
|
|
72
|
+
console.log(chalk.gray('\nCheck your address book: fuego addbook list'));
|
|
73
|
+
console.log(chalk.gray('Or use a full Solana address.'));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Validate amount
|
|
78
|
+
const amountNum = parseFloat(amount);
|
|
79
|
+
if (isNaN(amountNum) || amountNum <= 0) {
|
|
80
|
+
console.log(chalk.red('❌ Invalid amount. Please provide a positive number.'));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Determine token
|
|
85
|
+
const token = (options.token || '').toUpperCase();
|
|
86
|
+
if (!token) {
|
|
87
|
+
console.log(chalk.red('❌ Token is required. Use: --token SOL, --token USDC, or --token USDT'));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
if (!['SOL', 'USDC', 'USDT'].includes(token)) {
|
|
91
|
+
console.log(chalk.red('❌ Invalid token. Use: SOL, USDC, or USDT'));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Show transaction details
|
|
96
|
+
const isContact = recipient !== resolvedAddress;
|
|
97
|
+
showInfo('📝 Transaction Preview', [
|
|
98
|
+
`From: ${chalk.cyan(formatPublicKey(walletConfig.publicKey))}`,
|
|
99
|
+
`To: ${chalk.cyan(formatPublicKey(resolvedAddress))}${isContact ? chalk.gray(` (${recipient})`) : ''}`,
|
|
100
|
+
`Amount: ${chalk.yellow(amount)} ${chalk.cyan(token)}`,
|
|
101
|
+
`Network: ${chalk.gray('mainnet-beta')}`
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
// Confirm unless --yes
|
|
105
|
+
if (!options.yes) {
|
|
106
|
+
console.log();
|
|
107
|
+
console.log(chalk.yellow('⚠️ Add --yes to confirm and send'));
|
|
108
|
+
flameDivider();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log();
|
|
113
|
+
console.log(chalk.blue('⏳ Executing transaction via Fuego...'));
|
|
114
|
+
|
|
115
|
+
// Find fuego installation path and call Python script
|
|
116
|
+
const fuegoPath = findFuegoPath();
|
|
117
|
+
if (!fuegoPath) {
|
|
118
|
+
showError('Fuego installation not found. Run "fuego install" first.');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const scriptPath = path.join(fuegoPath, 'scripts', 'fuego_transfer.py');
|
|
123
|
+
|
|
124
|
+
const pythonProcess = spawn('python3', [
|
|
125
|
+
scriptPath,
|
|
126
|
+
'--from', walletConfig.publicKey,
|
|
127
|
+
'--to', resolvedAddress,
|
|
128
|
+
'--amount', amount,
|
|
129
|
+
'--token', token
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
let output = '';
|
|
133
|
+
let errorOutput = '';
|
|
134
|
+
|
|
135
|
+
pythonProcess.stdout.on('data', (data) => {
|
|
136
|
+
output += data.toString();
|
|
137
|
+
process.stdout.write(data);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
pythonProcess.stderr.on('data', (data) => {
|
|
141
|
+
errorOutput += data.toString();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
pythonProcess.on('close', (code) => {
|
|
145
|
+
if (code === 0) {
|
|
146
|
+
// Extract signature from output if present
|
|
147
|
+
const sigMatch = output.match(/Signature: ([A-Za-z0-9]+)/);
|
|
148
|
+
if (sigMatch) {
|
|
149
|
+
showSuccess(
|
|
150
|
+
'✅ Transaction Sent!',
|
|
151
|
+
`Amount: ${chalk.yellow(amount)} ${chalk.cyan(token)}\nTo: ${chalk.cyan(isContact ? recipient : formatPublicKey(resolvedAddress))}`
|
|
152
|
+
);
|
|
153
|
+
} else {
|
|
154
|
+
showSuccess('✅ Transaction Complete!', '');
|
|
155
|
+
}
|
|
156
|
+
flameDivider();
|
|
157
|
+
} else {
|
|
158
|
+
showError(`Transaction failed: ${errorOutput || 'Unknown error'}`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,9 @@ import { balanceCommand } from './commands/balance.js';
|
|
|
9
9
|
import { serveCommand } from './commands/serve.js';
|
|
10
10
|
import { dashboardCommand } from './commands/dashboard.js';
|
|
11
11
|
import { updateCommand } from './commands/update.js';
|
|
12
|
+
import { addRpcCommand } from './commands/addrpc.js';
|
|
13
|
+
import { addBookAddCommand, addBookListCommand, addBookShowCommand, addBookRemoveCommand } from './commands/addbook.js';
|
|
14
|
+
import { sendCommand } from './commands/send.js';
|
|
12
15
|
import { showBanner } from './lib/ascii.js';
|
|
13
16
|
|
|
14
17
|
async function main() {
|
|
@@ -72,6 +75,46 @@ async function main() {
|
|
|
72
75
|
.option('--fuego', 'Update only the fuego project')
|
|
73
76
|
.action(updateCommand);
|
|
74
77
|
|
|
78
|
+
program
|
|
79
|
+
.command('addrpc')
|
|
80
|
+
.description('Add or update your Solana RPC endpoint')
|
|
81
|
+
.option('-u, --url <url>', 'RPC endpoint URL (e.g., https://api.mainnet-beta.solana.com)')
|
|
82
|
+
.option('-n, --network <network>', 'Network type (mainnet, devnet, testnet)', 'mainnet')
|
|
83
|
+
.action(addRpcCommand);
|
|
84
|
+
|
|
85
|
+
const addbook = program
|
|
86
|
+
.command('addbook')
|
|
87
|
+
.description('Manage your address book (stored in ~/.fuego/contacts/address-book.json)');
|
|
88
|
+
|
|
89
|
+
addbook
|
|
90
|
+
.command('add <name> <address>')
|
|
91
|
+
.description('Add a contact to your address book')
|
|
92
|
+
.option('-l, --label <label>', 'Optional description/label for this contact')
|
|
93
|
+
.action(addBookAddCommand);
|
|
94
|
+
|
|
95
|
+
addbook
|
|
96
|
+
.command('list')
|
|
97
|
+
.description('List all contacts in your address book')
|
|
98
|
+
.action(addBookListCommand);
|
|
99
|
+
|
|
100
|
+
addbook
|
|
101
|
+
.command('show <name>')
|
|
102
|
+
.description('Show details for a specific contact')
|
|
103
|
+
.action(addBookShowCommand);
|
|
104
|
+
|
|
105
|
+
addbook
|
|
106
|
+
.command('remove <name>')
|
|
107
|
+
.description('Remove a contact from your address book')
|
|
108
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
109
|
+
.action(addBookRemoveCommand);
|
|
110
|
+
|
|
111
|
+
program
|
|
112
|
+
.command('send <recipient> <amount>')
|
|
113
|
+
.description('Send SOL, USDC, or USDT to an address or contact')
|
|
114
|
+
.requiredOption('-t, --token <token>', 'Token to send (SOL, USDC, USDT)')
|
|
115
|
+
.option('-y, --yes', 'Skip confirmation and send immediately')
|
|
116
|
+
.action(sendCommand);
|
|
117
|
+
|
|
75
118
|
await program.parseAsync(process.argv);
|
|
76
119
|
}
|
|
77
120
|
|
package/fuego-cli-0.1.0.tgz
DELETED
|
Binary file
|
package/fuego-cli-1.0.0.tgz
DELETED
|
Binary file
|