@grimoirelabs/cli 0.14.2 → 0.15.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/dist/commands/advisory-handlers.d.ts.map +1 -1
- package/dist/commands/advisory-handlers.js +1 -180
- package/dist/commands/advisory-handlers.js.map +1 -1
- package/dist/commands/advisory-live-trace.d.ts.map +1 -1
- package/dist/commands/advisory-live-trace.js +1 -1
- package/dist/commands/advisory-live-trace.js.map +1 -1
- package/dist/commands/advisory-verbose-trace.d.ts +15 -0
- package/dist/commands/advisory-verbose-trace.d.ts.map +1 -0
- package/dist/commands/advisory-verbose-trace.js +185 -0
- package/dist/commands/advisory-verbose-trace.js.map +1 -0
- package/dist/commands/cast-cross-chain.d.ts +69 -0
- package/dist/commands/cast-cross-chain.d.ts.map +1 -0
- package/dist/commands/cast-cross-chain.js +456 -0
- package/dist/commands/cast-cross-chain.js.map +1 -0
- package/dist/commands/cast.d.ts +1 -1
- package/dist/commands/cast.d.ts.map +1 -1
- package/dist/commands/cast.js +84 -709
- package/dist/commands/cast.js.map +1 -1
- package/dist/commands/compile-all.d.ts +15 -2
- package/dist/commands/compile-all.d.ts.map +1 -1
- package/dist/commands/compile-all.js +16 -21
- package/dist/commands/compile-all.js.map +1 -1
- package/dist/commands/compile.d.ts +1 -1
- package/dist/commands/compile.d.ts.map +1 -1
- package/dist/commands/compile.js +22 -26
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/cross-chain-helpers.d.ts +0 -1
- package/dist/commands/cross-chain-helpers.d.ts.map +1 -1
- package/dist/commands/cross-chain-helpers.js +0 -3
- package/dist/commands/cross-chain-helpers.js.map +1 -1
- package/dist/commands/history.d.ts +1 -2
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +59 -69
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +25 -20
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/log.d.ts +1 -2
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +9 -12
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/resume.d.ts +18 -1
- package/dist/commands/resume.d.ts.map +1 -1
- package/dist/commands/resume.js +44 -66
- package/dist/commands/resume.js.map +1 -1
- package/dist/commands/setup-ui.d.ts +46 -0
- package/dist/commands/setup-ui.d.ts.map +1 -0
- package/dist/commands/setup-ui.js +221 -0
- package/dist/commands/setup-ui.js.map +1 -0
- package/dist/commands/setup.d.ts +31 -3
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +27 -270
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/simulate-cross-chain.d.ts +53 -0
- package/dist/commands/simulate-cross-chain.d.ts.map +1 -0
- package/dist/commands/simulate-cross-chain.js +256 -0
- package/dist/commands/simulate-cross-chain.js.map +1 -0
- package/dist/commands/simulate.d.ts +5 -1
- package/dist/commands/simulate.d.ts.map +1 -1
- package/dist/commands/simulate.js +16 -364
- package/dist/commands/simulate.js.map +1 -1
- package/dist/commands/state-helpers.d.ts.map +1 -1
- package/dist/commands/state-helpers.js +1 -5
- package/dist/commands/state-helpers.js.map +1 -1
- package/dist/commands/validate.d.ts +24 -2
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +40 -42
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/venue-doctor-morpho.d.ts +38 -0
- package/dist/commands/venue-doctor-morpho.d.ts.map +1 -0
- package/dist/commands/venue-doctor-morpho.js +214 -0
- package/dist/commands/venue-doctor-morpho.js.map +1 -0
- package/dist/commands/venue-doctor.d.ts +2 -26
- package/dist/commands/venue-doctor.d.ts.map +1 -1
- package/dist/commands/venue-doctor.js +17 -221
- package/dist/commands/venue-doctor.js.map +1 -1
- package/dist/commands/venue.d.ts.map +1 -1
- package/dist/commands/venue.js +11 -19
- package/dist/commands/venue.js.map +1 -1
- package/dist/commands/venues.d.ts +1 -5
- package/dist/commands/venues.d.ts.map +1 -1
- package/dist/commands/venues.js +5 -8
- package/dist/commands/venues.js.map +1 -1
- package/dist/commands/wallet-weth.d.ts +22 -0
- package/dist/commands/wallet-weth.d.ts.map +1 -0
- package/dist/commands/wallet-weth.js +150 -0
- package/dist/commands/wallet-weth.js.map +1 -0
- package/dist/commands/wallet.d.ts +65 -3
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +183 -377
- package/dist/commands/wallet.js.map +1 -1
- package/dist/index.js +375 -170
- package/dist/index.js.map +1 -1
- package/dist/lib/execution-helpers.d.ts +24 -0
- package/dist/lib/execution-helpers.d.ts.map +1 -0
- package/dist/lib/execution-helpers.js +133 -0
- package/dist/lib/execution-helpers.js.map +1 -0
- package/dist/lib/json.d.ts +8 -0
- package/dist/lib/json.d.ts.map +1 -0
- package/dist/lib/json.js +10 -0
- package/dist/lib/json.js.map +1 -0
- package/dist/lib/keystore.d.ts +12 -0
- package/dist/lib/keystore.d.ts.map +1 -0
- package/dist/lib/keystore.js +14 -0
- package/dist/lib/keystore.js.map +1 -0
- package/dist/lib/prompts.d.ts +16 -0
- package/dist/lib/prompts.d.ts.map +1 -0
- package/dist/lib/prompts.js +61 -0
- package/dist/lib/prompts.js.map +1 -0
- package/package.json +4 -4
package/dist/commands/wallet.js
CHANGED
|
@@ -1,47 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wallet Command
|
|
3
|
-
* Manage wallet lifecycle: generate, address, balance, import
|
|
3
|
+
* Manage wallet lifecycle: generate, address, balance, import, wrap, unwrap
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import * as readline from "node:readline";
|
|
9
|
-
import { Writable } from "node:stream";
|
|
10
|
-
import { createKeystore, createProvider, createWalletFromConfig, formatWei, generatePrivateKey, getAddressFromConfig, getChainName, getNativeCurrencySymbol, } from "@grimoirelabs/core";
|
|
6
|
+
import { dirname } from "node:path";
|
|
7
|
+
import { createKeystore, createProvider, formatWei, generatePrivateKey, getAddressFromConfig, getChainName, getNativeCurrencySymbol, } from "@grimoirelabs/core";
|
|
11
8
|
import chalk from "chalk";
|
|
12
|
-
import {
|
|
9
|
+
import { Cli, z } from "incur";
|
|
13
10
|
import ora from "ora";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* Resolve the keystore file path from options or default
|
|
18
|
-
*/
|
|
19
|
-
function resolveKeystorePath(options) {
|
|
20
|
-
return options.keystore ?? DEFAULT_KEYSTORE_PATH;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Prompt for a password interactively (hides input)
|
|
24
|
-
*/
|
|
25
|
-
async function promptPassword(message) {
|
|
26
|
-
return new Promise((resolve) => {
|
|
27
|
-
process.stdout.write(message);
|
|
28
|
-
const silentOutput = new Writable({
|
|
29
|
-
write(_chunk, _encoding, cb) {
|
|
30
|
-
cb();
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
const rl = readline.createInterface({
|
|
34
|
-
input: process.stdin,
|
|
35
|
-
output: silentOutput,
|
|
36
|
-
terminal: true,
|
|
37
|
-
});
|
|
38
|
-
rl.question("", (answer) => {
|
|
39
|
-
rl.close();
|
|
40
|
-
process.stdout.write("\n");
|
|
41
|
-
resolve(answer);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}
|
|
11
|
+
import { resolveKeystorePath } from "../lib/keystore.js";
|
|
12
|
+
import { promptPassword } from "../lib/prompts.js";
|
|
13
|
+
import { unwrapAction, wrapAction } from "./wallet-weth.js";
|
|
45
14
|
/**
|
|
46
15
|
* Resolve keystore password from env var, interactive prompt, or error
|
|
47
16
|
*/
|
|
@@ -78,360 +47,197 @@ async function resolveNewKeystorePassword(options) {
|
|
|
78
47
|
}
|
|
79
48
|
throw new Error(`No password available. Set ${envName} or run interactively.`);
|
|
80
49
|
}
|
|
81
|
-
// ──
|
|
82
|
-
async function
|
|
50
|
+
// ── Subcommand handlers ────────────────────────────────────────────
|
|
51
|
+
async function generateHandler(options) {
|
|
83
52
|
const spinner = ora("Generating wallet...").start();
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
output.privateKey = privateKey;
|
|
111
|
-
}
|
|
112
|
-
console.log(JSON.stringify(output, null, 2));
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
console.log(` ${chalk.dim("Address:")} ${address}`);
|
|
116
|
-
console.log(` ${chalk.dim("Keystore:")} ${keystorePath}`);
|
|
117
|
-
if (options.printKey) {
|
|
118
|
-
console.log();
|
|
119
|
-
console.log(chalk.yellow(" WARNING: Store this private key securely. It will not be shown again."));
|
|
120
|
-
console.log(` ${chalk.dim("Private key:")} ${privateKey}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (error) {
|
|
125
|
-
spinner.fail(chalk.red(`Failed: ${error.message}`));
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
53
|
+
const privateKey = generatePrivateKey();
|
|
54
|
+
const address = getAddressFromConfig({ type: "raw", source: privateKey });
|
|
55
|
+
spinner.text = "Waiting for password...";
|
|
56
|
+
spinner.stop();
|
|
57
|
+
const password = await resolveNewKeystorePassword(options);
|
|
58
|
+
spinner.start("Encrypting keystore...");
|
|
59
|
+
const keystoreJson = await createKeystore(privateKey, password);
|
|
60
|
+
const keystorePath = resolveKeystorePath(options);
|
|
61
|
+
const dir = dirname(keystorePath);
|
|
62
|
+
if (!existsSync(dir)) {
|
|
63
|
+
mkdirSync(dir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
writeFileSync(keystorePath, keystoreJson, "utf-8");
|
|
66
|
+
spinner.succeed(chalk.green("Wallet generated"));
|
|
67
|
+
const output = { address, keystore: keystorePath };
|
|
68
|
+
if (options.printKey) {
|
|
69
|
+
console.error();
|
|
70
|
+
console.error(chalk.yellow(" WARNING: Store this private key securely. It will not be shown again."));
|
|
71
|
+
console.error(` ${chalk.dim("Private key:")} ${privateKey}`);
|
|
72
|
+
output.privateKey = privateKey;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.error(` ${chalk.dim("Address:")} ${address}`);
|
|
76
|
+
console.error(` ${chalk.dim("Keystore:")} ${keystorePath}`);
|
|
77
|
+
}
|
|
78
|
+
return output;
|
|
128
79
|
}
|
|
129
|
-
async function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
keyConfig = { type: "mnemonic", source: options.mnemonic };
|
|
134
|
-
}
|
|
135
|
-
else if (options.keyEnv) {
|
|
136
|
-
keyConfig = { type: "env", source: options.keyEnv };
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// Default: keystore
|
|
140
|
-
const keystorePath = resolveKeystorePath(options);
|
|
141
|
-
if (!existsSync(keystorePath)) {
|
|
142
|
-
console.error(chalk.red(`Keystore not found: ${keystorePath}`));
|
|
143
|
-
console.error(chalk.dim("Run 'grimoire wallet generate' to create one."));
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
const password = await resolveKeystorePassword(options);
|
|
147
|
-
const keystoreJson = readFileSync(keystorePath, "utf-8");
|
|
148
|
-
keyConfig = { type: "keystore", source: keystoreJson, password };
|
|
149
|
-
}
|
|
150
|
-
const address = getAddressFromConfig(keyConfig);
|
|
151
|
-
if (options.json) {
|
|
152
|
-
console.log(JSON.stringify({ address }));
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
console.log(address);
|
|
156
|
-
}
|
|
80
|
+
async function addressHandler(options) {
|
|
81
|
+
let keyConfig;
|
|
82
|
+
if (options.mnemonic) {
|
|
83
|
+
keyConfig = { type: "mnemonic", source: options.mnemonic };
|
|
157
84
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
process.exit(1);
|
|
85
|
+
else if (options.keyEnv) {
|
|
86
|
+
keyConfig = { type: "env", source: options.keyEnv };
|
|
161
87
|
}
|
|
162
|
-
|
|
163
|
-
async function balanceAction(options) {
|
|
164
|
-
try {
|
|
165
|
-
let keyConfig;
|
|
166
|
-
if (options.mnemonic) {
|
|
167
|
-
keyConfig = { type: "mnemonic", source: options.mnemonic };
|
|
168
|
-
}
|
|
169
|
-
else if (options.keyEnv) {
|
|
170
|
-
keyConfig = { type: "env", source: options.keyEnv };
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
const keystorePath = resolveKeystorePath(options);
|
|
174
|
-
if (!existsSync(keystorePath)) {
|
|
175
|
-
console.error(chalk.red(`Keystore not found: ${keystorePath}`));
|
|
176
|
-
console.error(chalk.dim("Run 'grimoire wallet generate' to create one."));
|
|
177
|
-
process.exit(1);
|
|
178
|
-
}
|
|
179
|
-
const password = await resolveKeystorePassword(options);
|
|
180
|
-
const keystoreJson = readFileSync(keystorePath, "utf-8");
|
|
181
|
-
keyConfig = { type: "keystore", source: keystoreJson, password };
|
|
182
|
-
}
|
|
183
|
-
const address = getAddressFromConfig(keyConfig);
|
|
184
|
-
const chainId = Number.parseInt(options.chain ?? "1", 10);
|
|
185
|
-
const chainName = getChainName(chainId);
|
|
186
|
-
const spinner = ora(`Fetching balance on ${chainName}...`).start();
|
|
187
|
-
const provider = createProvider(chainId, options.rpcUrl);
|
|
188
|
-
const balance = await provider.getBalance(address);
|
|
189
|
-
spinner.succeed(chalk.green("Balance retrieved"));
|
|
190
|
-
if (options.json) {
|
|
191
|
-
console.log(JSON.stringify({
|
|
192
|
-
address,
|
|
193
|
-
chain: chainId,
|
|
194
|
-
chainName,
|
|
195
|
-
balanceWei: balance.toString(),
|
|
196
|
-
balance: formatWei(balance),
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
console.log(` ${chalk.dim("Address:")} ${address}`);
|
|
201
|
-
console.log(` ${chalk.dim("Chain:")} ${chainName} (${chainId})`);
|
|
202
|
-
console.log(` ${chalk.dim("Balance:")} ${formatWei(balance)} ${getNativeCurrencySymbol(chainId)}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
catch (error) {
|
|
206
|
-
console.error(chalk.red(`Failed: ${error.message}`));
|
|
207
|
-
process.exit(1);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async function importAction(options) {
|
|
211
|
-
const spinner = ora("Importing wallet...").start();
|
|
212
|
-
try {
|
|
213
|
-
// Load existing key from env
|
|
214
|
-
const envName = options.keyEnv ?? "PRIVATE_KEY";
|
|
215
|
-
const rawKey = process.env[envName];
|
|
216
|
-
if (!rawKey) {
|
|
217
|
-
spinner.fail(chalk.red(`Environment variable ${envName} is not set`));
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
220
|
-
// Derive address for validation
|
|
221
|
-
const address = getAddressFromConfig({ type: "raw", source: rawKey });
|
|
222
|
-
spinner.text = "Waiting for password...";
|
|
223
|
-
spinner.stop();
|
|
224
|
-
// Prompt new keystore password
|
|
225
|
-
const password = await resolveNewKeystorePassword(options);
|
|
226
|
-
spinner.start("Encrypting keystore...");
|
|
227
|
-
// Normalize key
|
|
228
|
-
const normalizedKey = rawKey.startsWith("0x") ? rawKey : `0x${rawKey}`;
|
|
229
|
-
// Encrypt
|
|
230
|
-
const keystoreJson = await createKeystore(normalizedKey, password);
|
|
231
|
-
// Write file
|
|
232
|
-
const keystorePath = resolveKeystorePath(options);
|
|
233
|
-
const dir = dirname(keystorePath);
|
|
234
|
-
if (!existsSync(dir)) {
|
|
235
|
-
mkdirSync(dir, { recursive: true });
|
|
236
|
-
}
|
|
237
|
-
writeFileSync(keystorePath, keystoreJson, "utf-8");
|
|
238
|
-
spinner.succeed(chalk.green("Wallet imported"));
|
|
239
|
-
if (options.json) {
|
|
240
|
-
console.log(JSON.stringify({ address, keystore: keystorePath }));
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
console.log(` ${chalk.dim("Address:")} ${address}`);
|
|
244
|
-
console.log(` ${chalk.dim("Keystore:")} ${keystorePath}`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
spinner.fail(chalk.red(`Failed: ${error.message}`));
|
|
249
|
-
process.exit(1);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
// ── WETH Constants ──────────────────────────────────────────────────
|
|
253
|
-
const WETH_ADDRESSES = {
|
|
254
|
-
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
255
|
-
8453: "0x4200000000000000000000000000000000000006",
|
|
256
|
-
10: "0x4200000000000000000000000000000000000006",
|
|
257
|
-
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
258
|
-
};
|
|
259
|
-
const WETH_DEPOSIT_SELECTOR = "0xd0e30db0";
|
|
260
|
-
const WETH_WITHDRAW_SELECTOR = "0x2e1a7d4d";
|
|
261
|
-
function ethToWei(eth) {
|
|
262
|
-
const [whole = "0", frac = ""] = eth.split(".");
|
|
263
|
-
const padded = frac.padEnd(18, "0").slice(0, 18);
|
|
264
|
-
return BigInt(whole) * 10n ** 18n + BigInt(padded);
|
|
265
|
-
}
|
|
266
|
-
async function wrapAction(options) {
|
|
267
|
-
try {
|
|
88
|
+
else {
|
|
268
89
|
const keystorePath = resolveKeystorePath(options);
|
|
269
90
|
if (!existsSync(keystorePath)) {
|
|
270
|
-
|
|
271
|
-
console.error(chalk.dim("Run 'grimoire wallet generate' to create one."));
|
|
272
|
-
process.exit(1);
|
|
91
|
+
throw new Error(`Keystore not found: ${keystorePath}. Run 'grimoire wallet generate' to create one.`);
|
|
273
92
|
}
|
|
274
93
|
const password = await resolveKeystorePassword(options);
|
|
275
94
|
const keystoreJson = readFileSync(keystorePath, "utf-8");
|
|
276
|
-
|
|
277
|
-
const chainId = Number.parseInt(options.chain ?? "8453", 10);
|
|
278
|
-
const nativeSymbol = getNativeCurrencySymbol(chainId);
|
|
279
|
-
if (nativeSymbol !== "ETH") {
|
|
280
|
-
console.error(chalk.red(`WETH only exists on ETH-native chains. Chain ${chainId} uses ${nativeSymbol}.`));
|
|
281
|
-
process.exit(1);
|
|
282
|
-
}
|
|
283
|
-
const wethAddress = WETH_ADDRESSES[chainId];
|
|
284
|
-
if (!wethAddress) {
|
|
285
|
-
console.error(chalk.red(`No known WETH address for chain ${chainId}`));
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
const provider = createProvider(chainId, options.rpcUrl);
|
|
289
|
-
const wallet = createWalletFromConfig(keyConfig, chainId, provider.rpcUrl);
|
|
290
|
-
const amountWei = ethToWei(options.amount);
|
|
291
|
-
const spinner = ora(`Wrapping ${options.amount} ETH → WETH on chain ${chainId}...`).start();
|
|
292
|
-
const receipt = await wallet.sendTransaction({
|
|
293
|
-
to: wethAddress,
|
|
294
|
-
value: amountWei,
|
|
295
|
-
data: WETH_DEPOSIT_SELECTOR,
|
|
296
|
-
});
|
|
297
|
-
if (receipt.status === "reverted") {
|
|
298
|
-
spinner.fail(chalk.red("Transaction reverted"));
|
|
299
|
-
console.error(` Tx: ${receipt.hash}`);
|
|
300
|
-
process.exit(1);
|
|
301
|
-
}
|
|
302
|
-
spinner.succeed(chalk.green(`Wrapped ${options.amount} ETH → WETH`));
|
|
303
|
-
const balance = await provider.getBalance(wallet.address);
|
|
304
|
-
if (options.json) {
|
|
305
|
-
console.log(JSON.stringify({
|
|
306
|
-
tx: receipt.hash,
|
|
307
|
-
amount: options.amount,
|
|
308
|
-
chain: chainId,
|
|
309
|
-
balance: formatWei(balance),
|
|
310
|
-
}));
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
console.log(` ${chalk.dim("Tx:")} ${receipt.hash}`);
|
|
314
|
-
console.log(` ${chalk.dim("Balance:")} ${formatWei(balance)} ETH`);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
catch (error) {
|
|
318
|
-
console.error(chalk.red(`Failed: ${error.message}`));
|
|
319
|
-
process.exit(1);
|
|
95
|
+
keyConfig = { type: "keystore", source: keystoreJson, password };
|
|
320
96
|
}
|
|
97
|
+
const address = getAddressFromConfig(keyConfig);
|
|
98
|
+
console.error(address);
|
|
99
|
+
return { address };
|
|
321
100
|
}
|
|
322
|
-
async function
|
|
323
|
-
|
|
101
|
+
async function balanceHandler(options) {
|
|
102
|
+
let keyConfig;
|
|
103
|
+
if (options.mnemonic) {
|
|
104
|
+
keyConfig = { type: "mnemonic", source: options.mnemonic };
|
|
105
|
+
}
|
|
106
|
+
else if (options.keyEnv) {
|
|
107
|
+
keyConfig = { type: "env", source: options.keyEnv };
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
324
110
|
const keystorePath = resolveKeystorePath(options);
|
|
325
111
|
if (!existsSync(keystorePath)) {
|
|
326
|
-
|
|
327
|
-
console.error(chalk.dim("Run 'grimoire wallet generate' to create one."));
|
|
328
|
-
process.exit(1);
|
|
112
|
+
throw new Error(`Keystore not found: ${keystorePath}. Run 'grimoire wallet generate' to create one.`);
|
|
329
113
|
}
|
|
330
114
|
const password = await resolveKeystorePassword(options);
|
|
331
115
|
const keystoreJson = readFileSync(keystorePath, "utf-8");
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
116
|
+
keyConfig = { type: "keystore", source: keystoreJson, password };
|
|
117
|
+
}
|
|
118
|
+
const address = getAddressFromConfig(keyConfig);
|
|
119
|
+
const chainId = Number.parseInt(options.chain ?? "1", 10);
|
|
120
|
+
const chainName = getChainName(chainId);
|
|
121
|
+
const spinner = ora(`Fetching balance on ${chainName}...`).start();
|
|
122
|
+
const provider = createProvider(chainId, options.rpcUrl);
|
|
123
|
+
const balance = await provider.getBalance(address);
|
|
124
|
+
spinner.succeed(chalk.green("Balance retrieved"));
|
|
125
|
+
console.error(` ${chalk.dim("Address:")} ${address}`);
|
|
126
|
+
console.error(` ${chalk.dim("Chain:")} ${chainName} (${chainId})`);
|
|
127
|
+
console.error(` ${chalk.dim("Balance:")} ${formatWei(balance)} ${getNativeCurrencySymbol(chainId)}`);
|
|
128
|
+
return {
|
|
129
|
+
address,
|
|
130
|
+
chain: chainId,
|
|
131
|
+
chainName,
|
|
132
|
+
balanceWei: balance.toString(),
|
|
133
|
+
balance: formatWei(balance),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function importHandler(options) {
|
|
137
|
+
const spinner = ora("Importing wallet...").start();
|
|
138
|
+
const envName = options.keyEnv ?? "PRIVATE_KEY";
|
|
139
|
+
const rawKey = process.env[envName];
|
|
140
|
+
if (!rawKey) {
|
|
141
|
+
spinner.fail(chalk.red(`Environment variable ${envName} is not set`));
|
|
142
|
+
throw new Error(`Environment variable ${envName} is not set`);
|
|
143
|
+
}
|
|
144
|
+
const address = getAddressFromConfig({ type: "raw", source: rawKey });
|
|
145
|
+
spinner.text = "Waiting for password...";
|
|
146
|
+
spinner.stop();
|
|
147
|
+
const password = await resolveNewKeystorePassword(options);
|
|
148
|
+
spinner.start("Encrypting keystore...");
|
|
149
|
+
const normalizedKey = rawKey.startsWith("0x") ? rawKey : `0x${rawKey}`;
|
|
150
|
+
const keystoreJson = await createKeystore(normalizedKey, password);
|
|
151
|
+
const keystorePath = resolveKeystorePath(options);
|
|
152
|
+
const dir = dirname(keystorePath);
|
|
153
|
+
if (!existsSync(dir)) {
|
|
154
|
+
mkdirSync(dir, { recursive: true });
|
|
155
|
+
}
|
|
156
|
+
writeFileSync(keystorePath, keystoreJson, "utf-8");
|
|
157
|
+
spinner.succeed(chalk.green("Wallet imported"));
|
|
158
|
+
console.error(` ${chalk.dim("Address:")} ${address}`);
|
|
159
|
+
console.error(` ${chalk.dim("Keystore:")} ${keystorePath}`);
|
|
160
|
+
return { address, keystore: keystorePath };
|
|
378
161
|
}
|
|
379
|
-
// ──
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
.
|
|
389
|
-
|
|
390
|
-
.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
.
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
.
|
|
423
|
-
|
|
424
|
-
.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
.
|
|
162
|
+
// ── Shared option schemas ──────────────────────────────────────────
|
|
163
|
+
const keystoreOptions = z.object({
|
|
164
|
+
keystore: z.string().optional().describe("Path to keystore file"),
|
|
165
|
+
passwordEnv: z.string().optional().describe("Environment variable for keystore password"),
|
|
166
|
+
});
|
|
167
|
+
// ── Incur CLI ──────────────────────────────────────────────────────
|
|
168
|
+
export const walletCli = Cli.create("wallet", {
|
|
169
|
+
description: "Manage wallets and keystores",
|
|
170
|
+
})
|
|
171
|
+
.command("generate", {
|
|
172
|
+
description: "Generate a new wallet and save to keystore",
|
|
173
|
+
options: keystoreOptions.extend({
|
|
174
|
+
printKey: z.boolean().optional().describe("Print the private key (one-time backup)"),
|
|
175
|
+
}),
|
|
176
|
+
async run(c) {
|
|
177
|
+
const result = await generateHandler(c.options);
|
|
178
|
+
return c.ok(result, { cta: { commands: ["wallet address", "wallet balance"] } });
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
.command("address", {
|
|
182
|
+
description: "Show wallet address",
|
|
183
|
+
options: keystoreOptions.extend({
|
|
184
|
+
keyEnv: z.string().optional().describe("Environment variable containing private key"),
|
|
185
|
+
mnemonic: z.string().optional().describe("Mnemonic phrase"),
|
|
186
|
+
}),
|
|
187
|
+
async run(c) {
|
|
188
|
+
const result = await addressHandler(c.options);
|
|
189
|
+
return c.ok(result);
|
|
190
|
+
},
|
|
191
|
+
})
|
|
192
|
+
.command("balance", {
|
|
193
|
+
description: "Check wallet balance",
|
|
194
|
+
options: keystoreOptions.extend({
|
|
195
|
+
keyEnv: z.string().optional().describe("Environment variable containing private key"),
|
|
196
|
+
mnemonic: z.string().optional().describe("Mnemonic phrase"),
|
|
197
|
+
chain: z.string().optional().default("1").describe("Chain ID"),
|
|
198
|
+
rpcUrl: z.string().optional().describe("RPC URL"),
|
|
199
|
+
}),
|
|
200
|
+
async run(c) {
|
|
201
|
+
const result = await balanceHandler(c.options);
|
|
202
|
+
return c.ok(result);
|
|
203
|
+
},
|
|
204
|
+
})
|
|
205
|
+
.command("import", {
|
|
206
|
+
description: "Import an existing private key into a keystore",
|
|
207
|
+
options: keystoreOptions.extend({
|
|
208
|
+
keyEnv: z
|
|
209
|
+
.string()
|
|
210
|
+
.optional()
|
|
211
|
+
.default("PRIVATE_KEY")
|
|
212
|
+
.describe("Environment variable containing private key"),
|
|
213
|
+
}),
|
|
214
|
+
async run(c) {
|
|
215
|
+
const result = await importHandler(c.options);
|
|
216
|
+
return c.ok(result, { cta: { commands: ["wallet balance"] } });
|
|
217
|
+
},
|
|
218
|
+
})
|
|
219
|
+
.command("wrap", {
|
|
220
|
+
description: "Wrap native currency to WETH",
|
|
221
|
+
options: keystoreOptions.extend({
|
|
222
|
+
amount: z.string().describe("Amount to wrap"),
|
|
223
|
+
chain: z.string().optional().default("8453").describe("Chain ID"),
|
|
224
|
+
rpcUrl: z.string().optional().describe("RPC URL"),
|
|
225
|
+
}),
|
|
226
|
+
async run(c) {
|
|
227
|
+
await wrapAction(c.options);
|
|
228
|
+
return c.ok({ success: true });
|
|
229
|
+
},
|
|
230
|
+
})
|
|
231
|
+
.command("unwrap", {
|
|
232
|
+
description: "Unwrap WETH to native currency",
|
|
233
|
+
options: keystoreOptions.extend({
|
|
234
|
+
amount: z.string().describe("Amount to unwrap"),
|
|
235
|
+
chain: z.string().optional().default("8453").describe("Chain ID"),
|
|
236
|
+
rpcUrl: z.string().optional().describe("RPC URL"),
|
|
237
|
+
}),
|
|
238
|
+
async run(c) {
|
|
239
|
+
await unwrapAction(c.options);
|
|
240
|
+
return c.ok({ success: true });
|
|
241
|
+
},
|
|
242
|
+
});
|
|
437
243
|
//# sourceMappingURL=wallet.js.map
|