genlayer 0.34.0 → 0.34.3
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/index.js +13 -3
- package/package.json +11 -2
- package/.eslintignore +0 -2
- package/.github/workflows/cli-docs.yml +0 -121
- package/.github/workflows/publish-beta.yml +0 -41
- package/.github/workflows/publish.yml +0 -43
- package/.github/workflows/validate-code.yml +0 -47
- package/.prettierignore +0 -19
- package/.prettierrc +0 -12
- package/.release-it.json +0 -64
- package/CHANGELOG.md +0 -425
- package/CLAUDE.md +0 -55
- package/CONTRIBUTING.md +0 -117
- package/docker-compose.yml +0 -154
- package/docs/delegator-guide.md +0 -203
- package/docs/validator-guide.md +0 -329
- package/esbuild.config.dev.js +0 -17
- package/esbuild.config.js +0 -22
- package/esbuild.config.prod.js +0 -17
- package/eslint.config.js +0 -60
- package/renovate.json +0 -22
- package/src/commands/account/create.ts +0 -30
- package/src/commands/account/export.ts +0 -106
- package/src/commands/account/import.ts +0 -135
- package/src/commands/account/index.ts +0 -129
- package/src/commands/account/list.ts +0 -34
- package/src/commands/account/lock.ts +0 -39
- package/src/commands/account/remove.ts +0 -30
- package/src/commands/account/send.ts +0 -162
- package/src/commands/account/show.ts +0 -74
- package/src/commands/account/unlock.ts +0 -56
- package/src/commands/account/use.ts +0 -21
- package/src/commands/config/getSetReset.ts +0 -51
- package/src/commands/config/index.ts +0 -30
- package/src/commands/contracts/call.ts +0 -39
- package/src/commands/contracts/code.ts +0 -33
- package/src/commands/contracts/deploy.ts +0 -157
- package/src/commands/contracts/index.ts +0 -86
- package/src/commands/contracts/schema.ts +0 -31
- package/src/commands/contracts/write.ts +0 -49
- package/src/commands/general/index.ts +0 -45
- package/src/commands/general/init.ts +0 -179
- package/src/commands/general/start.ts +0 -116
- package/src/commands/general/stop.ts +0 -26
- package/src/commands/localnet/index.ts +0 -100
- package/src/commands/localnet/validators.ts +0 -269
- package/src/commands/network/index.ts +0 -29
- package/src/commands/network/setNetwork.ts +0 -77
- package/src/commands/scaffold/index.ts +0 -16
- package/src/commands/scaffold/new.ts +0 -34
- package/src/commands/staking/StakingAction.ts +0 -279
- package/src/commands/staking/delegatorClaim.ts +0 -41
- package/src/commands/staking/delegatorExit.ts +0 -56
- package/src/commands/staking/delegatorJoin.ts +0 -44
- package/src/commands/staking/index.ts +0 -357
- package/src/commands/staking/setIdentity.ts +0 -78
- package/src/commands/staking/setOperator.ts +0 -46
- package/src/commands/staking/stakingInfo.ts +0 -584
- package/src/commands/staking/validatorClaim.ts +0 -43
- package/src/commands/staking/validatorDeposit.ts +0 -48
- package/src/commands/staking/validatorExit.ts +0 -63
- package/src/commands/staking/validatorHistory.ts +0 -298
- package/src/commands/staking/validatorJoin.ts +0 -47
- package/src/commands/staking/validatorPrime.ts +0 -73
- package/src/commands/staking/wizard.ts +0 -809
- package/src/commands/transactions/appeal.ts +0 -39
- package/src/commands/transactions/index.ts +0 -39
- package/src/commands/transactions/receipt.ts +0 -90
- package/src/commands/update/index.ts +0 -25
- package/src/commands/update/ollama.ts +0 -103
- package/src/lib/actions/BaseAction.ts +0 -299
- package/src/lib/clients/jsonRpcClient.ts +0 -41
- package/src/lib/clients/system.ts +0 -73
- package/src/lib/config/ConfigFileManager.ts +0 -194
- package/src/lib/config/KeychainManager.ts +0 -89
- package/src/lib/config/simulator.ts +0 -68
- package/src/lib/config/text.ts +0 -2
- package/src/lib/errors/missingRequirement.ts +0 -9
- package/src/lib/errors/versionRequired.ts +0 -9
- package/src/lib/interfaces/ISimulatorService.ts +0 -37
- package/src/lib/services/simulator.ts +0 -351
- package/src/types/node-fetch.d.ts +0 -1
- package/tests/actions/appeal.test.ts +0 -99
- package/tests/actions/call.test.ts +0 -94
- package/tests/actions/code.test.ts +0 -87
- package/tests/actions/create.test.ts +0 -65
- package/tests/actions/deploy.test.ts +0 -420
- package/tests/actions/getSetReset.test.ts +0 -88
- package/tests/actions/init.test.ts +0 -467
- package/tests/actions/lock.test.ts +0 -86
- package/tests/actions/new.test.ts +0 -80
- package/tests/actions/ollama.test.ts +0 -193
- package/tests/actions/receipt.test.ts +0 -261
- package/tests/actions/schema.test.ts +0 -94
- package/tests/actions/setNetwork.test.ts +0 -160
- package/tests/actions/staking.test.ts +0 -279
- package/tests/actions/start.test.ts +0 -235
- package/tests/actions/stop.test.ts +0 -77
- package/tests/actions/unlock.test.ts +0 -139
- package/tests/actions/validators.test.ts +0 -750
- package/tests/actions/write.test.ts +0 -102
- package/tests/commands/account.test.ts +0 -146
- package/tests/commands/appeal.test.ts +0 -58
- package/tests/commands/call.test.ts +0 -78
- package/tests/commands/code.test.ts +0 -69
- package/tests/commands/config.test.ts +0 -54
- package/tests/commands/deploy.test.ts +0 -83
- package/tests/commands/init.test.ts +0 -101
- package/tests/commands/localnet.test.ts +0 -131
- package/tests/commands/network.test.ts +0 -60
- package/tests/commands/new.test.ts +0 -68
- package/tests/commands/receipt.test.ts +0 -142
- package/tests/commands/schema.test.ts +0 -67
- package/tests/commands/staking.test.ts +0 -329
- package/tests/commands/stop.test.ts +0 -27
- package/tests/commands/up.test.ts +0 -105
- package/tests/commands/update.test.ts +0 -45
- package/tests/commands/write.test.ts +0 -76
- package/tests/index.test.ts +0 -56
- package/tests/libs/baseAction.test.ts +0 -516
- package/tests/libs/configFileManager.test.ts +0 -117
- package/tests/libs/jsonRpcClient.test.ts +0 -59
- package/tests/libs/keychainManager.test.ts +0 -156
- package/tests/libs/system.test.ts +0 -148
- package/tests/services/simulator.test.ts +0 -705
- package/tests/utils.ts +0 -13
- package/tsconfig.json +0 -120
- package/vitest.config.ts +0 -12
package/esbuild.config.prod.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
context: {
|
|
3
|
-
tsconfig: "./tsconfig.json",
|
|
4
|
-
entryPoints: ["src/index.ts"],
|
|
5
|
-
bundle: true,
|
|
6
|
-
outfile: "dist/index.js",
|
|
7
|
-
platform: "node",
|
|
8
|
-
target: "es2020",
|
|
9
|
-
format: "esm",
|
|
10
|
-
define: { "import.meta.url": "import.meta.url" },
|
|
11
|
-
banner: {
|
|
12
|
-
js: `const _importMetaUrl = new URL(import.meta.url).pathname;`,
|
|
13
|
-
},
|
|
14
|
-
external: ["commander", "dockerode", "dotenv", "ethers", "inquirer", "update-check", "ssh2", "fs-extra", "esbuild", "keytar"]
|
|
15
|
-
},
|
|
16
|
-
watch: false,
|
|
17
|
-
};
|
package/eslint.config.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import js from "@eslint/js";
|
|
2
|
-
import tseslint from "@typescript-eslint/eslint-plugin";
|
|
3
|
-
import tsparser from "@typescript-eslint/parser";
|
|
4
|
-
import prettier from "eslint-config-prettier";
|
|
5
|
-
import importPlugin from "eslint-plugin-import";
|
|
6
|
-
|
|
7
|
-
export default [
|
|
8
|
-
js.configs.recommended,
|
|
9
|
-
prettier,
|
|
10
|
-
{
|
|
11
|
-
languageOptions: {
|
|
12
|
-
parser: tsparser,
|
|
13
|
-
parserOptions: {
|
|
14
|
-
project: ["./tsconfig.json"],
|
|
15
|
-
sourceType: "module",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
ignores: [
|
|
19
|
-
"**/dist/**/*",
|
|
20
|
-
"esbuild.config.js",
|
|
21
|
-
"esbuild.config.dev.js",
|
|
22
|
-
"esbuild.config.prod.js",
|
|
23
|
-
"jest.config.js",
|
|
24
|
-
"eslint.config.js",
|
|
25
|
-
"Config.js",
|
|
26
|
-
"commitLint.config.ts",
|
|
27
|
-
"scripts/postinstall.js",
|
|
28
|
-
"templates/**/*"
|
|
29
|
-
],
|
|
30
|
-
plugins: {
|
|
31
|
-
"@typescript-eslint": tseslint,
|
|
32
|
-
import: importPlugin,
|
|
33
|
-
},
|
|
34
|
-
rules: {
|
|
35
|
-
"import/namespace": "off",
|
|
36
|
-
"@typescript-eslint/no-empty-function": "off",
|
|
37
|
-
"@typescript-eslint/no-empty-interface": "off",
|
|
38
|
-
"no-constant-condition": "off",
|
|
39
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
40
|
-
"prefer-const": "off",
|
|
41
|
-
"@typescript-eslint/no-non-null-assertion": "off",
|
|
42
|
-
"@typescript-eslint/ban-ts-ignore": "off",
|
|
43
|
-
"@typescript-eslint/no-loss-of-precision": "off",
|
|
44
|
-
"@typescript-eslint/ban-types": "off",
|
|
45
|
-
"@typescript-eslint/ban-ts-comment": "off",
|
|
46
|
-
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
|
|
47
|
-
"@typescript-eslint/no-var-requires": "off",
|
|
48
|
-
"import/export": "off",
|
|
49
|
-
"no-fallthrough": "off",
|
|
50
|
-
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
51
|
-
"@typescript-eslint/no-floating-promises": ["error"],
|
|
52
|
-
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
|
|
53
|
-
},
|
|
54
|
-
settings: {
|
|
55
|
-
"import/resolver": {
|
|
56
|
-
typescript: {},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
];
|
package/renovate.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
-
"extends": [
|
|
4
|
-
"config:recommended"
|
|
5
|
-
],
|
|
6
|
-
"ignorePaths": [
|
|
7
|
-
"templates/**"
|
|
8
|
-
],
|
|
9
|
-
"packageRules": [
|
|
10
|
-
{
|
|
11
|
-
"groupName": "all non-major dependencies",
|
|
12
|
-
"groupSlug": "all-minor-patch",
|
|
13
|
-
"matchPackageNames": [
|
|
14
|
-
"*"
|
|
15
|
-
],
|
|
16
|
-
"matchUpdateTypes": [
|
|
17
|
-
"minor",
|
|
18
|
-
"patch"
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
|
|
3
|
-
export interface CreateAccountOptions {
|
|
4
|
-
name: string;
|
|
5
|
-
overwrite: boolean;
|
|
6
|
-
setActive?: boolean;
|
|
7
|
-
password?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class CreateAccountAction extends BaseAction {
|
|
11
|
-
constructor() {
|
|
12
|
-
super();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async execute(options: CreateAccountOptions): Promise<void> {
|
|
16
|
-
try {
|
|
17
|
-
this.startSpinner(`Creating account '${options.name}'...`);
|
|
18
|
-
await this.createKeypairByName(options.name, options.overwrite, options.password);
|
|
19
|
-
|
|
20
|
-
if (options.setActive !== false) {
|
|
21
|
-
this.setActiveAccount(options.name);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const keystorePath = this.getKeystorePath(options.name);
|
|
25
|
-
this.succeedSpinner(`Account '${options.name}' created at: ${keystorePath}`);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
this.failSpinner("Failed to create account", error);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
import {ethers} from "ethers";
|
|
3
|
-
import {writeFileSync, existsSync, readFileSync} from "fs";
|
|
4
|
-
import path from "path";
|
|
5
|
-
|
|
6
|
-
export interface ExportAccountOptions {
|
|
7
|
-
account?: string;
|
|
8
|
-
output: string;
|
|
9
|
-
password?: string;
|
|
10
|
-
sourcePassword?: string;
|
|
11
|
-
overwrite?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class ExportAccountAction extends BaseAction {
|
|
15
|
-
constructor() {
|
|
16
|
-
super();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async execute(options: ExportAccountOptions): Promise<void> {
|
|
20
|
-
try {
|
|
21
|
-
if (options.account) {
|
|
22
|
-
this.accountOverride = options.account;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const accountName = this.resolveAccountName();
|
|
26
|
-
const keystorePath = this.getKeystorePath(accountName);
|
|
27
|
-
|
|
28
|
-
if (!existsSync(keystorePath)) {
|
|
29
|
-
this.failSpinner(`Account '${accountName}' not found.`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const outputPath = path.resolve(options.output);
|
|
33
|
-
|
|
34
|
-
if (existsSync(outputPath) && !options.overwrite) {
|
|
35
|
-
this.failSpinner(`Output file already exists: ${outputPath}`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Get the private key
|
|
39
|
-
const privateKey = await this.getPrivateKeyForExport(accountName, keystorePath, options.sourcePassword);
|
|
40
|
-
|
|
41
|
-
// Get password for the exported keystore
|
|
42
|
-
let password: string;
|
|
43
|
-
if (options.password) {
|
|
44
|
-
password = options.password;
|
|
45
|
-
} else {
|
|
46
|
-
password = await this.promptPassword("Enter password for exported keystore (minimum 8 characters):");
|
|
47
|
-
const confirmPassword = await this.promptPassword("Confirm password:");
|
|
48
|
-
if (password !== confirmPassword) {
|
|
49
|
-
this.failSpinner("Passwords do not match");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (password.length < BaseAction.MIN_PASSWORD_LENGTH) {
|
|
54
|
-
this.failSpinner(`Password must be at least ${BaseAction.MIN_PASSWORD_LENGTH} characters long`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.startSpinner(`Exporting account '${accountName}'...`);
|
|
58
|
-
|
|
59
|
-
const wallet = new ethers.Wallet(privateKey);
|
|
60
|
-
const encryptedJson = await wallet.encrypt(password);
|
|
61
|
-
|
|
62
|
-
// Write standard web3 keystore format (compatible with geth, foundry, etc.)
|
|
63
|
-
writeFileSync(outputPath, encryptedJson);
|
|
64
|
-
|
|
65
|
-
this.succeedSpinner(`Account '${accountName}' exported to: ${outputPath}`);
|
|
66
|
-
this.logInfo(`Address: ${wallet.address}`);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
this.failSpinner("Failed to export account", error);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private async getPrivateKeyForExport(
|
|
73
|
-
accountName: string,
|
|
74
|
-
keystorePath: string,
|
|
75
|
-
sourcePassword?: string
|
|
76
|
-
): Promise<string> {
|
|
77
|
-
// First check if key is cached in keychain
|
|
78
|
-
const isAvailable = await this.keychainManager.isKeychainAvailable();
|
|
79
|
-
if (isAvailable) {
|
|
80
|
-
const cachedKey = await this.keychainManager.getPrivateKey(accountName);
|
|
81
|
-
if (cachedKey) {
|
|
82
|
-
return cachedKey;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Need to decrypt the keystore
|
|
87
|
-
const fileContent = readFileSync(keystorePath, "utf-8");
|
|
88
|
-
const parsed = JSON.parse(fileContent);
|
|
89
|
-
|
|
90
|
-
const encryptedJson = parsed.encrypted || fileContent;
|
|
91
|
-
|
|
92
|
-
const password = sourcePassword || await this.promptPassword(`Enter password to unlock '${accountName}':`);
|
|
93
|
-
|
|
94
|
-
this.startSpinner("Decrypting keystore...");
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
const wallet = await ethers.Wallet.fromEncryptedJson(encryptedJson, password);
|
|
98
|
-
this.stopSpinner();
|
|
99
|
-
return wallet.privateKey;
|
|
100
|
-
} catch {
|
|
101
|
-
this.failSpinner("Failed to decrypt keystore. Wrong password?");
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
throw new Error("Unreachable");
|
|
105
|
-
}
|
|
106
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
import {ethers} from "ethers";
|
|
3
|
-
import {writeFileSync, existsSync, readFileSync} from "fs";
|
|
4
|
-
|
|
5
|
-
export interface ImportAccountOptions {
|
|
6
|
-
privateKey?: string;
|
|
7
|
-
keystore?: string;
|
|
8
|
-
name: string;
|
|
9
|
-
overwrite: boolean;
|
|
10
|
-
setActive?: boolean;
|
|
11
|
-
password?: string;
|
|
12
|
-
sourcePassword?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class ImportAccountAction extends BaseAction {
|
|
16
|
-
constructor() {
|
|
17
|
-
super();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async execute(options: ImportAccountOptions): Promise<void> {
|
|
21
|
-
try {
|
|
22
|
-
const keystorePath = this.getKeystorePath(options.name);
|
|
23
|
-
|
|
24
|
-
if (existsSync(keystorePath) && !options.overwrite) {
|
|
25
|
-
this.failSpinner(`Account '${options.name}' already exists. Use '--overwrite' to replace.`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let privateKey: string;
|
|
29
|
-
|
|
30
|
-
if (options.keystore) {
|
|
31
|
-
privateKey = await this.importFromKeystore(options.keystore, options.sourcePassword);
|
|
32
|
-
} else if (options.privateKey) {
|
|
33
|
-
const normalizedKey = this.normalizePrivateKey(options.privateKey);
|
|
34
|
-
this.validatePrivateKey(normalizedKey);
|
|
35
|
-
privateKey = normalizedKey;
|
|
36
|
-
} else {
|
|
37
|
-
const inputKey = await this.promptPrivateKey();
|
|
38
|
-
const normalizedKey = this.normalizePrivateKey(inputKey);
|
|
39
|
-
this.validatePrivateKey(normalizedKey);
|
|
40
|
-
privateKey = normalizedKey;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const wallet = new ethers.Wallet(privateKey);
|
|
44
|
-
|
|
45
|
-
let password: string;
|
|
46
|
-
if (options.password) {
|
|
47
|
-
password = options.password;
|
|
48
|
-
} else {
|
|
49
|
-
password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
|
|
50
|
-
const confirmPassword = await this.promptPassword("Confirm password:");
|
|
51
|
-
if (password !== confirmPassword) {
|
|
52
|
-
this.failSpinner("Passwords do not match");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (password.length < BaseAction.MIN_PASSWORD_LENGTH) {
|
|
57
|
-
this.failSpinner(`Password must be at least ${BaseAction.MIN_PASSWORD_LENGTH} characters long`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this.startSpinner(`Importing account '${options.name}'...`);
|
|
61
|
-
|
|
62
|
-
const encryptedJson = await wallet.encrypt(password);
|
|
63
|
-
|
|
64
|
-
// Write standard web3 keystore format directly
|
|
65
|
-
writeFileSync(keystorePath, encryptedJson);
|
|
66
|
-
|
|
67
|
-
if (options.setActive !== false) {
|
|
68
|
-
this.setActiveAccount(options.name);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
await this.keychainManager.removePrivateKey(options.name);
|
|
72
|
-
|
|
73
|
-
this.succeedSpinner(`Account '${options.name}' imported to: ${keystorePath}`);
|
|
74
|
-
this.logInfo(`Address: ${wallet.address}`);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
this.failSpinner("Failed to import account", error);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private async importFromKeystore(keystorePath: string, sourcePassword?: string): Promise<string> {
|
|
81
|
-
if (!existsSync(keystorePath)) {
|
|
82
|
-
this.failSpinner(`Keystore file not found: ${keystorePath}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const fileContent = readFileSync(keystorePath, "utf-8");
|
|
86
|
-
let encryptedJson: string;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const parsed = JSON.parse(fileContent);
|
|
90
|
-
|
|
91
|
-
// Check if it's our format (with 'encrypted' field) or standard web3 keystore
|
|
92
|
-
if (parsed.encrypted) {
|
|
93
|
-
// Our format
|
|
94
|
-
encryptedJson = parsed.encrypted;
|
|
95
|
-
} else if (parsed.crypto || parsed.Crypto) {
|
|
96
|
-
// Standard web3 keystore format (geth, foundry, etc.)
|
|
97
|
-
encryptedJson = fileContent;
|
|
98
|
-
} else {
|
|
99
|
-
this.failSpinner("Invalid keystore format. Expected encrypted keystore file.");
|
|
100
|
-
}
|
|
101
|
-
} catch {
|
|
102
|
-
this.failSpinner("Invalid keystore file. Could not parse JSON.");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const password = sourcePassword || await this.promptPassword("Enter password to decrypt keystore:");
|
|
106
|
-
|
|
107
|
-
this.startSpinner("Decrypting keystore...");
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
const wallet = await ethers.Wallet.fromEncryptedJson(encryptedJson!, password);
|
|
111
|
-
this.stopSpinner();
|
|
112
|
-
return wallet.privateKey;
|
|
113
|
-
} catch {
|
|
114
|
-
this.failSpinner("Failed to decrypt keystore. Wrong password?");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// This line is unreachable but TypeScript needs it
|
|
118
|
-
throw new Error("Unreachable");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private async promptPrivateKey(): Promise<string> {
|
|
122
|
-
return this.promptPassword("Enter private key to import:");
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private normalizePrivateKey(key: string): string {
|
|
126
|
-
const trimmed = key.trim();
|
|
127
|
-
return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private validatePrivateKey(key: string): void {
|
|
131
|
-
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
132
|
-
this.failSpinner("Invalid private key format. Expected 64 hex characters (with or without 0x prefix).");
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import {Command} from "commander";
|
|
2
|
-
import {ShowAccountAction, ShowAccountOptions} from "./show";
|
|
3
|
-
import {CreateAccountAction, CreateAccountOptions} from "./create";
|
|
4
|
-
import {ImportAccountAction, ImportAccountOptions} from "./import";
|
|
5
|
-
import {ExportAccountAction, ExportAccountOptions} from "./export";
|
|
6
|
-
import {UnlockAccountAction, UnlockAccountOptions} from "./unlock";
|
|
7
|
-
import {LockAccountAction, LockAccountOptions} from "./lock";
|
|
8
|
-
import {SendAction, SendOptions} from "./send";
|
|
9
|
-
import {ListAccountsAction} from "./list";
|
|
10
|
-
import {UseAccountAction} from "./use";
|
|
11
|
-
import {RemoveAccountAction} from "./remove";
|
|
12
|
-
|
|
13
|
-
export function initializeAccountCommands(program: Command) {
|
|
14
|
-
const accountCommand = program
|
|
15
|
-
.command("account")
|
|
16
|
-
.description("Manage your accounts (address, balance, keys)")
|
|
17
|
-
.action(async () => {
|
|
18
|
-
// Default action: show account info (use 'account show' for options)
|
|
19
|
-
const showAction = new ShowAccountAction();
|
|
20
|
-
await showAction.execute({});
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
accountCommand
|
|
24
|
-
.command("list")
|
|
25
|
-
.description("List all accounts")
|
|
26
|
-
.action(async () => {
|
|
27
|
-
const listAction = new ListAccountsAction();
|
|
28
|
-
await listAction.execute();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
accountCommand
|
|
32
|
-
.command("show")
|
|
33
|
-
.description("Show account details (address, balance)")
|
|
34
|
-
.option("--rpc <rpcUrl>", "RPC URL for the network")
|
|
35
|
-
.option("--account <name>", "Account to show")
|
|
36
|
-
.action(async (options: ShowAccountOptions) => {
|
|
37
|
-
const showAction = new ShowAccountAction();
|
|
38
|
-
await showAction.execute(options);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
accountCommand
|
|
42
|
-
.command("create")
|
|
43
|
-
.description("Create a new account with encrypted keystore")
|
|
44
|
-
.requiredOption("--name <name>", "Name for the account")
|
|
45
|
-
.option("--password <password>", "Password for the keystore (skips interactive prompt)")
|
|
46
|
-
.option("--overwrite", "Overwrite existing account", false)
|
|
47
|
-
.option("--no-set-active", "Do not set as active account")
|
|
48
|
-
.action(async (options: CreateAccountOptions) => {
|
|
49
|
-
const createAction = new CreateAccountAction();
|
|
50
|
-
await createAction.execute(options);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
accountCommand
|
|
54
|
-
.command("import")
|
|
55
|
-
.description("Import an account from a private key or keystore file")
|
|
56
|
-
.requiredOption("--name <name>", "Name for the account")
|
|
57
|
-
.option("--private-key <key>", "Private key to import")
|
|
58
|
-
.option("--keystore <path>", "Path to keystore file to import (geth, foundry, etc.)")
|
|
59
|
-
.option("--password <password>", "Password for the new keystore (skips confirmation prompt)")
|
|
60
|
-
.option("--source-password <password>", "Password to decrypt source keystore (with --keystore)")
|
|
61
|
-
.option("--overwrite", "Overwrite existing account", false)
|
|
62
|
-
.option("--no-set-active", "Do not set as active account")
|
|
63
|
-
.action(async (options: ImportAccountOptions) => {
|
|
64
|
-
const importAction = new ImportAccountAction();
|
|
65
|
-
await importAction.execute(options);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
accountCommand
|
|
69
|
-
.command("export")
|
|
70
|
-
.description("Export an account to a keystore file (web3/geth/foundry compatible)")
|
|
71
|
-
.requiredOption("--output <path>", "Output path for the keystore file")
|
|
72
|
-
.option("--account <name>", "Account to export (defaults to active account)")
|
|
73
|
-
.option("--password <password>", "Password for exported keystore (skips confirmation)")
|
|
74
|
-
.option("--source-password <password>", "Password to decrypt account (if not unlocked)")
|
|
75
|
-
.action(async (options: ExportAccountOptions) => {
|
|
76
|
-
const exportAction = new ExportAccountAction();
|
|
77
|
-
await exportAction.execute(options);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
accountCommand
|
|
81
|
-
.command("use <name>")
|
|
82
|
-
.description("Set the active account")
|
|
83
|
-
.action(async (name: string) => {
|
|
84
|
-
const useAction = new UseAccountAction();
|
|
85
|
-
await useAction.execute(name);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
accountCommand
|
|
89
|
-
.command("remove <name>")
|
|
90
|
-
.description("Remove an account")
|
|
91
|
-
.option("--force", "Skip confirmation prompt", false)
|
|
92
|
-
.action(async (name: string, options: {force?: boolean}) => {
|
|
93
|
-
const removeAction = new RemoveAccountAction();
|
|
94
|
-
await removeAction.execute(name, options);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
accountCommand
|
|
98
|
-
.command("send <to> <amount>")
|
|
99
|
-
.description("Send GEN to an address")
|
|
100
|
-
.option("--rpc <rpcUrl>", "RPC URL for the network")
|
|
101
|
-
.option("--network <network>", "Network to use (localnet, testnet-asimov)")
|
|
102
|
-
.option("--account <name>", "Account to send from")
|
|
103
|
-
.option("--password <password>", "Password to unlock account (skips interactive prompt)")
|
|
104
|
-
.action(async (to: string, amount: string, options: {rpc?: string; network?: string; account?: string; password?: string}) => {
|
|
105
|
-
const sendAction = new SendAction();
|
|
106
|
-
await sendAction.execute({to, amount, rpc: options.rpc, network: options.network, account: options.account, password: options.password});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
accountCommand
|
|
110
|
-
.command("unlock")
|
|
111
|
-
.description("Unlock account by caching private key in OS keychain")
|
|
112
|
-
.option("--account <name>", "Account to unlock")
|
|
113
|
-
.option("--password <password>", "Password to unlock account (skips interactive prompt)")
|
|
114
|
-
.action(async (options: UnlockAccountOptions) => {
|
|
115
|
-
const unlockAction = new UnlockAccountAction();
|
|
116
|
-
await unlockAction.execute(options);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
accountCommand
|
|
120
|
-
.command("lock")
|
|
121
|
-
.description("Lock account by removing private key from OS keychain")
|
|
122
|
-
.option("--account <name>", "Account to lock")
|
|
123
|
-
.action(async (options: LockAccountOptions) => {
|
|
124
|
-
const lockAction = new LockAccountAction();
|
|
125
|
-
await lockAction.execute(options);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
return program;
|
|
129
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
|
|
3
|
-
export class ListAccountsAction extends BaseAction {
|
|
4
|
-
constructor() {
|
|
5
|
-
super();
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
async execute(): Promise<void> {
|
|
9
|
-
try {
|
|
10
|
-
const accounts = this.listAccounts();
|
|
11
|
-
const activeAccount = this.getActiveAccount();
|
|
12
|
-
const unlockedAccounts = await this.keychainManager.listUnlockedAccounts();
|
|
13
|
-
|
|
14
|
-
if (accounts.length === 0) {
|
|
15
|
-
this.logInfo("No accounts found. Run 'genlayer account create --name <name>' to create one.");
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.log("");
|
|
20
|
-
for (const account of accounts) {
|
|
21
|
-
const isActive = account.name === activeAccount;
|
|
22
|
-
const isUnlocked = unlockedAccounts.includes(account.name);
|
|
23
|
-
const marker = isActive ? "*" : " ";
|
|
24
|
-
const status = isUnlocked ? "(unlocked)" : "";
|
|
25
|
-
const activeLabel = isActive ? "(active)" : "";
|
|
26
|
-
|
|
27
|
-
console.log(`${marker} ${account.name.padEnd(16)} ${account.address} ${activeLabel} ${status}`.trim());
|
|
28
|
-
}
|
|
29
|
-
console.log("");
|
|
30
|
-
} catch (error) {
|
|
31
|
-
this.failSpinner("Failed to list accounts", error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
|
|
3
|
-
export interface LockAccountOptions {
|
|
4
|
-
account?: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class LockAccountAction extends BaseAction {
|
|
8
|
-
async execute(options?: LockAccountOptions): Promise<void> {
|
|
9
|
-
this.startSpinner("Checking keychain availability...");
|
|
10
|
-
|
|
11
|
-
const keychainAvailable = await this.keychainManager.isKeychainAvailable();
|
|
12
|
-
if (!keychainAvailable) {
|
|
13
|
-
this.failSpinner("OS keychain is not available. This command requires a supported keychain (e.g. macOS Keychain, Windows Credential Manager, or GNOME Keyring).");
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (options?.account) {
|
|
18
|
-
this.accountOverride = options.account;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const accountName = this.resolveAccountName();
|
|
22
|
-
this.setSpinnerText(`Checking for cached private key for '${accountName}'...`);
|
|
23
|
-
|
|
24
|
-
const hasCachedKey = await this.keychainManager.getPrivateKey(accountName);
|
|
25
|
-
if (!hasCachedKey) {
|
|
26
|
-
this.succeedSpinner(`Account '${accountName}' is already locked.`);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
this.setSpinnerText(`Removing private key for '${accountName}' from OS keychain...`);
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
await this.keychainManager.removePrivateKey(accountName);
|
|
34
|
-
this.succeedSpinner(`Account '${accountName}' locked! Private key removed from OS keychain.`);
|
|
35
|
-
} catch (error) {
|
|
36
|
-
this.failSpinner("Failed to lock account.", error);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import {BaseAction} from "../../lib/actions/BaseAction";
|
|
2
|
-
|
|
3
|
-
export class RemoveAccountAction extends BaseAction {
|
|
4
|
-
constructor() {
|
|
5
|
-
super();
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
async execute(name: string, options: {force?: boolean}): Promise<void> {
|
|
9
|
-
try {
|
|
10
|
-
if (!this.accountExists(name)) {
|
|
11
|
-
this.failSpinner(`Account '${name}' does not exist.`);
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!options.force) {
|
|
16
|
-
await this.confirmPrompt(`Are you sure you want to remove account '${name}'? This cannot be undone.`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Remove from keychain if unlocked
|
|
20
|
-
await this.keychainManager.removePrivateKey(name);
|
|
21
|
-
|
|
22
|
-
// Remove keystore file
|
|
23
|
-
this.removeAccount(name);
|
|
24
|
-
|
|
25
|
-
this.logSuccess(`Account '${name}' removed`);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
this.failSpinner("Failed to remove account", error);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|