genlayer 0.33.1 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/dist/index.js +68 -31
  2. package/package.json +11 -2
  3. package/.eslintignore +0 -2
  4. package/.github/workflows/cli-docs.yml +0 -121
  5. package/.github/workflows/publish-beta.yml +0 -41
  6. package/.github/workflows/publish.yml +0 -43
  7. package/.github/workflows/validate-code.yml +0 -47
  8. package/.prettierignore +0 -19
  9. package/.prettierrc +0 -12
  10. package/.release-it.json +0 -64
  11. package/CHANGELOG.md +0 -419
  12. package/CLAUDE.md +0 -55
  13. package/CONTRIBUTING.md +0 -117
  14. package/docker-compose.yml +0 -154
  15. package/docs/delegator-guide.md +0 -203
  16. package/docs/validator-guide.md +0 -329
  17. package/esbuild.config.dev.js +0 -17
  18. package/esbuild.config.js +0 -22
  19. package/esbuild.config.prod.js +0 -17
  20. package/eslint.config.js +0 -60
  21. package/renovate.json +0 -22
  22. package/src/commands/account/create.ts +0 -29
  23. package/src/commands/account/export.ts +0 -106
  24. package/src/commands/account/import.ts +0 -135
  25. package/src/commands/account/index.ts +0 -126
  26. package/src/commands/account/list.ts +0 -34
  27. package/src/commands/account/lock.ts +0 -39
  28. package/src/commands/account/remove.ts +0 -30
  29. package/src/commands/account/send.ts +0 -156
  30. package/src/commands/account/show.ts +0 -74
  31. package/src/commands/account/unlock.ts +0 -51
  32. package/src/commands/account/use.ts +0 -21
  33. package/src/commands/config/getSetReset.ts +0 -51
  34. package/src/commands/config/index.ts +0 -30
  35. package/src/commands/contracts/call.ts +0 -39
  36. package/src/commands/contracts/code.ts +0 -33
  37. package/src/commands/contracts/deploy.ts +0 -157
  38. package/src/commands/contracts/index.ts +0 -86
  39. package/src/commands/contracts/schema.ts +0 -31
  40. package/src/commands/contracts/write.ts +0 -49
  41. package/src/commands/general/index.ts +0 -45
  42. package/src/commands/general/init.ts +0 -179
  43. package/src/commands/general/start.ts +0 -116
  44. package/src/commands/general/stop.ts +0 -26
  45. package/src/commands/localnet/index.ts +0 -100
  46. package/src/commands/localnet/validators.ts +0 -269
  47. package/src/commands/network/index.ts +0 -29
  48. package/src/commands/network/setNetwork.ts +0 -77
  49. package/src/commands/scaffold/index.ts +0 -16
  50. package/src/commands/scaffold/new.ts +0 -34
  51. package/src/commands/staking/StakingAction.ts +0 -267
  52. package/src/commands/staking/delegatorClaim.ts +0 -41
  53. package/src/commands/staking/delegatorExit.ts +0 -56
  54. package/src/commands/staking/delegatorJoin.ts +0 -44
  55. package/src/commands/staking/index.ts +0 -346
  56. package/src/commands/staking/setIdentity.ts +0 -78
  57. package/src/commands/staking/setOperator.ts +0 -46
  58. package/src/commands/staking/stakingInfo.ts +0 -584
  59. package/src/commands/staking/validatorClaim.ts +0 -43
  60. package/src/commands/staking/validatorDeposit.ts +0 -48
  61. package/src/commands/staking/validatorExit.ts +0 -63
  62. package/src/commands/staking/validatorHistory.ts +0 -298
  63. package/src/commands/staking/validatorJoin.ts +0 -47
  64. package/src/commands/staking/validatorPrime.ts +0 -73
  65. package/src/commands/staking/wizard.ts +0 -809
  66. package/src/commands/transactions/appeal.ts +0 -39
  67. package/src/commands/transactions/index.ts +0 -39
  68. package/src/commands/transactions/receipt.ts +0 -90
  69. package/src/commands/update/index.ts +0 -25
  70. package/src/commands/update/ollama.ts +0 -103
  71. package/src/lib/actions/BaseAction.ts +0 -295
  72. package/src/lib/clients/jsonRpcClient.ts +0 -41
  73. package/src/lib/clients/system.ts +0 -73
  74. package/src/lib/config/ConfigFileManager.ts +0 -194
  75. package/src/lib/config/KeychainManager.ts +0 -89
  76. package/src/lib/config/simulator.ts +0 -68
  77. package/src/lib/config/text.ts +0 -2
  78. package/src/lib/errors/missingRequirement.ts +0 -9
  79. package/src/lib/errors/versionRequired.ts +0 -9
  80. package/src/lib/interfaces/ISimulatorService.ts +0 -37
  81. package/src/lib/services/simulator.ts +0 -351
  82. package/src/types/node-fetch.d.ts +0 -1
  83. package/tests/actions/appeal.test.ts +0 -99
  84. package/tests/actions/call.test.ts +0 -94
  85. package/tests/actions/code.test.ts +0 -87
  86. package/tests/actions/create.test.ts +0 -65
  87. package/tests/actions/deploy.test.ts +0 -420
  88. package/tests/actions/getSetReset.test.ts +0 -88
  89. package/tests/actions/init.test.ts +0 -467
  90. package/tests/actions/lock.test.ts +0 -86
  91. package/tests/actions/new.test.ts +0 -80
  92. package/tests/actions/ollama.test.ts +0 -193
  93. package/tests/actions/receipt.test.ts +0 -261
  94. package/tests/actions/schema.test.ts +0 -94
  95. package/tests/actions/setNetwork.test.ts +0 -160
  96. package/tests/actions/staking.test.ts +0 -279
  97. package/tests/actions/start.test.ts +0 -235
  98. package/tests/actions/stop.test.ts +0 -77
  99. package/tests/actions/unlock.test.ts +0 -139
  100. package/tests/actions/validators.test.ts +0 -750
  101. package/tests/actions/write.test.ts +0 -102
  102. package/tests/commands/account.test.ts +0 -146
  103. package/tests/commands/appeal.test.ts +0 -58
  104. package/tests/commands/call.test.ts +0 -78
  105. package/tests/commands/code.test.ts +0 -69
  106. package/tests/commands/config.test.ts +0 -54
  107. package/tests/commands/deploy.test.ts +0 -83
  108. package/tests/commands/init.test.ts +0 -101
  109. package/tests/commands/localnet.test.ts +0 -131
  110. package/tests/commands/network.test.ts +0 -60
  111. package/tests/commands/new.test.ts +0 -68
  112. package/tests/commands/receipt.test.ts +0 -142
  113. package/tests/commands/schema.test.ts +0 -67
  114. package/tests/commands/staking.test.ts +0 -329
  115. package/tests/commands/stop.test.ts +0 -27
  116. package/tests/commands/up.test.ts +0 -105
  117. package/tests/commands/update.test.ts +0 -45
  118. package/tests/commands/write.test.ts +0 -76
  119. package/tests/index.test.ts +0 -56
  120. package/tests/libs/baseAction.test.ts +0 -516
  121. package/tests/libs/configFileManager.test.ts +0 -117
  122. package/tests/libs/jsonRpcClient.test.ts +0 -59
  123. package/tests/libs/keychainManager.test.ts +0 -156
  124. package/tests/libs/system.test.ts +0 -148
  125. package/tests/services/simulator.test.ts +0 -705
  126. package/tests/utils.ts +0 -13
  127. package/tsconfig.json +0 -120
  128. package/vitest.config.ts +0 -12
@@ -1,39 +0,0 @@
1
- import {TransactionHash} from "genlayer-js/types";
2
- import {BaseAction} from "../../lib/actions/BaseAction";
3
-
4
- export interface AppealOptions {
5
- rpc?: string;
6
- }
7
-
8
- export class AppealAction extends BaseAction {
9
- constructor() {
10
- super();
11
- }
12
-
13
- async appeal({
14
- txId,
15
- rpc,
16
- }: {
17
- txId: TransactionHash;
18
- rpc?: string;
19
- }): Promise<void> {
20
- const client = await this.getClient(rpc);
21
- await client.initializeConsensusSmartContract();
22
- this.startSpinner(`Appealing transaction ${txId}...`);
23
-
24
- try {
25
- const hash = await client.appealTransaction({
26
- txId,
27
- });
28
-
29
- const result = await client.waitForTransactionReceipt({
30
- hash,
31
- retries: 100,
32
- interval: 5000,
33
- });
34
- this.succeedSpinner("Appeal operation successfully executed", result);
35
- } catch (error) {
36
- this.failSpinner("Error during appeal operation", error);
37
- }
38
- }
39
- }
@@ -1,39 +0,0 @@
1
- import {Command} from "commander";
2
- import {TransactionStatus, TransactionHash} from "genlayer-js/types";
3
- import {ReceiptAction, ReceiptOptions} from "./receipt";
4
- import {AppealAction, AppealOptions} from "./appeal";
5
-
6
- function parseIntOption(value: string, fallback: number): number {
7
- const parsed = parseInt(value, 10);
8
- return isNaN(parsed) ? fallback : parsed;
9
- }
10
-
11
- export function initializeTransactionsCommands(program: Command) {
12
- const validStatuses = Object.values(TransactionStatus).join(", ");
13
-
14
- program
15
- .command("receipt <txId>")
16
- .description("Get transaction receipt by hash")
17
- .option("--status <status>", `Transaction status to wait for (${validStatuses})`, TransactionStatus.FINALIZED)
18
- .option("--retries <retries>", "Number of retries", (value) => parseIntOption(value, 100), 100)
19
- .option("--interval <interval>", "Interval between retries in milliseconds", (value) => parseIntOption(value, 5000), 5000)
20
- .option("--rpc <rpcUrl>", "RPC URL for the network")
21
- .option("--stdout", "Print only stdout from the receipt")
22
- .option("--stderr", "Print only stderr from the receipt")
23
- .action(async (txId: TransactionHash, options: ReceiptOptions) => {
24
- const receiptAction = new ReceiptAction();
25
-
26
- await receiptAction.receipt({txId, ...options});
27
- })
28
-
29
- program
30
- .command("appeal <txId>")
31
- .description("Appeal a transaction by its hash")
32
- .option("--rpc <rpcUrl>", "RPC URL for the network")
33
- .action(async (txId: TransactionHash, options: AppealOptions) => {
34
- const appealAction = new AppealAction();
35
- await appealAction.appeal({txId, ...options});
36
- });
37
-
38
- return program;
39
- }
@@ -1,90 +0,0 @@
1
- import {BaseAction} from "../../lib/actions/BaseAction";
2
- import {TransactionHash, TransactionStatus} from "genlayer-js/types";
3
-
4
- export interface ReceiptParams {
5
- txId: TransactionHash;
6
- status?: string | TransactionStatus;
7
- retries?: number;
8
- interval?: number;
9
- rpc?: string;
10
- stdout?: boolean;
11
- stderr?: boolean;
12
- }
13
-
14
- export interface ReceiptOptions extends Omit<ReceiptParams, 'txId'> {}
15
-
16
- export class ReceiptAction extends BaseAction {
17
- constructor() {
18
- super();
19
- }
20
-
21
- private validateTransactionStatus(status: string): TransactionStatus | undefined {
22
- const upperStatus = status.toUpperCase() as keyof typeof TransactionStatus;
23
-
24
- if (!(upperStatus in TransactionStatus)) {
25
- const validStatuses = Object.values(TransactionStatus);
26
- this.failSpinner(
27
- "Invalid transaction status",
28
- `Invalid status: ${status}. Valid values are: ${validStatuses.join(", ")}`
29
- );
30
- return
31
- }
32
-
33
- return TransactionStatus[upperStatus];
34
- }
35
-
36
- async receipt({
37
- txId,
38
- status = TransactionStatus.FINALIZED,
39
- retries,
40
- interval,
41
- rpc,
42
- stdout,
43
- stderr,
44
- }: ReceiptParams): Promise<void> {
45
- const client = await this.getClient(rpc);
46
- await client.initializeConsensusSmartContract();
47
- this.startSpinner(`Waiting for transaction receipt ${txId} (status: ${status})...`);
48
-
49
- try {
50
- let validatedStatus = this.validateTransactionStatus(status);
51
-
52
- if (!validatedStatus) {
53
- return;
54
- }
55
-
56
- const result = await client.waitForTransactionReceipt({
57
- hash: txId,
58
- status: validatedStatus,
59
- retries,
60
- interval,
61
- });
62
-
63
- // If specific output flags are provided, print only those fields
64
- if (stdout || stderr) {
65
- const stdoutValue = (result as any)?.consensus_data?.leader_receipt[0]?.genvm_result?.stdout;
66
- const stderrValue = (result as any)?.consensus_data?.leader_receipt[0]?.genvm_result?.stderr;
67
-
68
- if (stdout && stderr) {
69
- this.succeedSpinner("Transaction stdout and stderr", { stdout: stdoutValue, stderr: stderrValue });
70
- return;
71
- }
72
-
73
- if (stdout) {
74
- this.succeedSpinner("Transaction stdout retrieved successfully", stdoutValue);
75
- return;
76
- }
77
-
78
- if (stderr) {
79
- this.succeedSpinner("Transaction stderr retrieved successfully", stderrValue);
80
- return;
81
- }
82
- }
83
-
84
- // Default behavior (no flags): show full receipt result
85
- this.succeedSpinner("Transaction receipt retrieved successfully", result);
86
- } catch (error) {
87
- this.failSpinner("Error retrieving transaction receipt", error);
88
- }
89
- }
90
- }
@@ -1,25 +0,0 @@
1
- import { Command } from "commander";
2
- import { OllamaAction } from "./ollama";
3
-
4
- export function initializeUpdateCommands(program: Command) {
5
- const updateCommand = program
6
- .command("update")
7
- .description("Update resources like models or configurations");
8
-
9
- updateCommand
10
- .command("ollama")
11
- .description("Manage Ollama models (update or remove)")
12
- .option("--model [model-name]", "Specify the model to update or remove", '')
13
- .option("--remove", "Remove the specified model instead of updating")
14
- .action(async (options) => {
15
- const ollamaAction = new OllamaAction();
16
-
17
- if (options.remove) {
18
- await ollamaAction.removeModel(options.model);
19
- } else {
20
- await ollamaAction.updateModel(options.model);
21
- }
22
- });
23
-
24
- return program;
25
- }
@@ -1,103 +0,0 @@
1
- import Docker from "dockerode";
2
- import { rpcClient } from "../../lib/clients/jsonRpcClient";
3
- import { BaseAction } from "../../lib/actions/BaseAction";
4
-
5
- export class OllamaAction extends BaseAction {
6
- private docker: Docker;
7
-
8
- constructor() {
9
- super();
10
- this.docker = new Docker();
11
- }
12
-
13
- async updateModel(modelName: string) {
14
- try {
15
- this.startSpinner(`Updating model "${modelName}"...`);
16
-
17
- if(!modelName){
18
- modelName = this.getConfig().defaultOllamaModel;
19
- }
20
-
21
- const providersAndModels = await rpcClient.request({
22
- method: "sim_getProvidersAndModels",
23
- params: [],
24
- });
25
-
26
- const existingOllamaProvider = providersAndModels.result.find(
27
- (entry: any) => entry.plugin === "ollama"
28
- );
29
-
30
- if (!existingOllamaProvider) {
31
- return this.failSpinner("No existing 'ollama' provider found. Unable to add/update a model.");
32
- }
33
-
34
- await this.executeModelCommand("pull", modelName, `Model "${modelName}" updated successfully`);
35
-
36
- const existingModel = providersAndModels.result.some(
37
- (entry: any) => entry.plugin === "ollama" && entry.model === modelName
38
- );
39
- if (!existingModel) {
40
- this.startSpinner(`Adding model "${modelName}" to Provider Presets...`);
41
-
42
- const newModelConfig = {
43
- config: existingOllamaProvider.config,
44
- model: modelName,
45
- plugin: "ollama",
46
- plugin_config: existingOllamaProvider.plugin_config,
47
- provider: "ollama",
48
- };
49
-
50
- await rpcClient.request({
51
- method: "sim_addProvider",
52
- params: [newModelConfig],
53
- });
54
- this.succeedSpinner(`Model "${modelName}" added to Provider Presets successfully.`);
55
- }
56
- } catch (error) {
57
- this.failSpinner(`Error updating model "${modelName}"`, error);
58
- }
59
- }
60
-
61
- async removeModel(modelName: string) {
62
- await this.executeModelCommand("rm", modelName, `Model "${modelName}" removed successfully`);
63
- }
64
-
65
- private async executeModelCommand(command: string, modelName: string, successMessage: string) {
66
- try {
67
- this.startSpinner(`Executing '${command}' command on model "${modelName}"...`);
68
-
69
- let success = false;
70
- const ollamaContainer = this.docker.getContainer("genlayer-ollama");
71
- const exec = await ollamaContainer.exec({
72
- Cmd: ["ollama", command, modelName],
73
- AttachStdout: true,
74
- AttachStderr: true,
75
- });
76
- const stream = await exec.start({ Detach: false, Tty: false });
77
-
78
- stream.on("data", (chunk: any) => {
79
- const output = chunk.toString();
80
- this.setSpinnerText(output.trim());
81
-
82
- if (output.includes("success") || output.includes("deleted")) {
83
- success = true;
84
- }
85
- });
86
-
87
- await new Promise<void>((resolve, reject) => {
88
- stream.on("end", () => {
89
- if (success) {
90
- this.succeedSpinner(successMessage);
91
- resolve();
92
- } else {
93
- this.failSpinner(`Failed to execute '${command}' on model "${modelName}".`);
94
- reject('internal error');
95
- }
96
- });
97
- stream.on("error", reject);
98
- });
99
- } catch (error) {
100
- this.failSpinner(`Error executing command "${command}" on model "${modelName}"`, error);
101
- }
102
- }
103
- }
@@ -1,295 +0,0 @@
1
- import {ConfigFileManager} from "../../lib/config/ConfigFileManager";
2
- import {KeychainManager} from "../../lib/config/KeychainManager";
3
- import ora, {Ora} from "ora";
4
- import chalk from "chalk";
5
- import inquirer from "inquirer";
6
- import { inspect } from "util";
7
- import {createClient, createAccount} from "genlayer-js";
8
- import {localnet, studionet, testnetAsimov} from "genlayer-js/chains";
9
- import type {GenLayerClient, GenLayerChain, Hash, Address, Account} from "genlayer-js/types";
10
-
11
- // Built-in networks - always resolve fresh from genlayer-js
12
- export const BUILT_IN_NETWORKS: Record<string, GenLayerChain> = {
13
- "localnet": localnet,
14
- "studionet": studionet,
15
- "testnet-asimov": testnetAsimov,
16
- };
17
-
18
- /**
19
- * Resolves a stored network config to a fresh chain object.
20
- * Handles both new format (alias string) and old format (JSON object) for backwards compat.
21
- */
22
- export function resolveNetwork(stored: string | undefined): GenLayerChain {
23
- if (!stored) return localnet;
24
-
25
- // Try as alias first (new format)
26
- if (BUILT_IN_NETWORKS[stored]) {
27
- return BUILT_IN_NETWORKS[stored];
28
- }
29
-
30
- // Backwards compat: try parsing as JSON (old format)
31
- try {
32
- const parsed = JSON.parse(stored);
33
- // If it has a known name, use fresh version instead
34
- const alias = Object.entries(BUILT_IN_NETWORKS)
35
- .find(([_, chain]) => chain.name === parsed.name)?.[0];
36
- if (alias) {
37
- return BUILT_IN_NETWORKS[alias];
38
- }
39
- // Custom network - use as-is
40
- return parsed;
41
- } catch {
42
- throw new Error(`Unknown network: ${stored}`);
43
- }
44
- }
45
- import { ethers } from "ethers";
46
- import { writeFileSync, existsSync, readFileSync } from "fs";
47
-
48
- export class BaseAction extends ConfigFileManager {
49
- private static readonly DEFAULT_ACCOUNT_NAME = "default";
50
- private static readonly MAX_PASSWORD_ATTEMPTS = 3;
51
- protected static readonly MIN_PASSWORD_LENGTH = 8;
52
-
53
- private spinner: Ora;
54
- private _genlayerClient: GenLayerClient<GenLayerChain> | null = null;
55
- protected keychainManager: KeychainManager;
56
- protected accountOverride: string | null = null;
57
-
58
- constructor() {
59
- super();
60
- this.spinner = ora({text: "", spinner: "dots"});
61
- this.keychainManager = new KeychainManager();
62
- }
63
-
64
- private async decryptKeystore(keystoreJson: string, attempt: number = 1): Promise<string> {
65
- try {
66
- const message = attempt === 1
67
- ? "Enter password to decrypt keystore:"
68
- : `Invalid password. Attempt ${attempt}/${BaseAction.MAX_PASSWORD_ATTEMPTS} - Enter password to decrypt keystore:`;
69
- const password = await this.promptPassword(message);
70
- const wallet = await ethers.Wallet.fromEncryptedJson(keystoreJson, password);
71
-
72
- return wallet.privateKey;
73
- } catch (error) {
74
- if (attempt >= BaseAction.MAX_PASSWORD_ATTEMPTS) {
75
- this.failSpinner(`Maximum password attempts exceeded (${BaseAction.MAX_PASSWORD_ATTEMPTS}/${BaseAction.MAX_PASSWORD_ATTEMPTS}).`);
76
- }
77
- return await this.decryptKeystore(keystoreJson, attempt + 1);
78
- }
79
- }
80
-
81
- protected isValidKeystoreFormat(data: any): boolean {
82
- // Standard web3 keystore format has 'crypto' (or 'Crypto') and 'address' fields
83
- return Boolean(
84
- data &&
85
- (data.crypto || data.Crypto) &&
86
- typeof data.address === "string"
87
- );
88
- }
89
-
90
- private formatOutput(data: any): string {
91
- if (typeof data === "string") {
92
- return data;
93
- }
94
- return inspect(data, { depth: null, colors: false });
95
- }
96
-
97
- protected async getClient(rpcUrl?: string, readOnly: boolean = false): Promise<GenLayerClient<GenLayerChain>> {
98
- if (!this._genlayerClient) {
99
- const network = resolveNetwork(this.getConfig().network);
100
- const account = await this.getAccount(readOnly);
101
- this._genlayerClient = createClient({
102
- chain: network,
103
- endpoint: rpcUrl,
104
- account: account,
105
- });
106
- }
107
- return this._genlayerClient;
108
- }
109
-
110
- protected resolveAccountName(): string {
111
- // Priority: explicit override > config active account > default
112
- if (this.accountOverride) {
113
- return this.accountOverride;
114
- }
115
- const activeAccount = this.getActiveAccount();
116
- if (activeAccount) {
117
- return activeAccount;
118
- }
119
- return BaseAction.DEFAULT_ACCOUNT_NAME;
120
- }
121
-
122
- private async getAccount(readOnly: boolean = false): Promise<Account | Address> {
123
- const accountName = this.resolveAccountName();
124
- const keystorePath = this.getKeystorePath(accountName);
125
- let decryptedPrivateKey;
126
- let keystoreJson: string;
127
- let keystoreData: any;
128
-
129
- if (!existsSync(keystorePath)) {
130
- await this.confirmPrompt(`Account '${accountName}' not found. Would you like to create it?`);
131
- decryptedPrivateKey = await this.createKeypairByName(accountName, false);
132
- }
133
-
134
- keystoreJson = readFileSync(keystorePath, "utf-8");
135
- keystoreData = JSON.parse(keystoreJson);
136
-
137
- if (!this.isValidKeystoreFormat(keystoreData)) {
138
- this.failSpinner("Invalid keystore format. Expected encrypted keystore file.", undefined, false);
139
- await this.confirmPrompt(`Would you like to recreate account '${accountName}'?`);
140
- decryptedPrivateKey = await this.createKeypairByName(accountName, true);
141
- keystoreJson = readFileSync(keystorePath, "utf-8");
142
- keystoreData = JSON.parse(keystoreJson);
143
- }
144
-
145
- if (readOnly) {
146
- return this.getAddress(keystoreData);
147
- }
148
-
149
- if (!decryptedPrivateKey) {
150
- const cachedKey = await this.keychainManager.getPrivateKey(accountName);
151
- if (cachedKey) {
152
- // Verify cached key matches keystore address
153
- const tempAccount = createAccount(cachedKey as Hash);
154
- const cachedAddress = tempAccount.address.toLowerCase();
155
- const keystoreAddress = `0x${keystoreData.address.toLowerCase().replace(/^0x/, '')}`;
156
- if (cachedAddress === keystoreAddress) {
157
- decryptedPrivateKey = cachedKey;
158
- } else {
159
- // Cached key doesn't match keystore - invalidate it
160
- await this.keychainManager.removePrivateKey(accountName);
161
- decryptedPrivateKey = await this.decryptKeystore(keystoreJson);
162
- }
163
- } else {
164
- decryptedPrivateKey = await this.decryptKeystore(keystoreJson);
165
- }
166
- }
167
- return createAccount(decryptedPrivateKey as Hash);
168
- }
169
-
170
- private getAddress(keystoreData: any): Address {
171
- return keystoreData.address as Address;
172
- }
173
-
174
- protected async createKeypairByName(accountName: string, overwrite: boolean): Promise<string> {
175
- const keystorePath = this.getKeystorePath(accountName);
176
- this.stopSpinner();
177
-
178
- if (existsSync(keystorePath) && !overwrite) {
179
- this.failSpinner(`Account '${accountName}' already exists. Use '--overwrite' to replace it.`);
180
- }
181
-
182
- const wallet = ethers.Wallet.createRandom();
183
-
184
- const password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
185
- const confirmPassword = await this.promptPassword("Confirm password:");
186
-
187
- if (password !== confirmPassword) {
188
- this.failSpinner("Passwords do not match");
189
- }
190
-
191
- if (password.length < BaseAction.MIN_PASSWORD_LENGTH) {
192
- this.failSpinner(`Password must be at least ${BaseAction.MIN_PASSWORD_LENGTH} characters long`);
193
- }
194
-
195
- // Write standard web3 keystore format directly
196
- const encryptedJson = await wallet.encrypt(password);
197
- writeFileSync(keystorePath, encryptedJson);
198
-
199
- // Set as active account if no active account exists
200
- if (!this.getActiveAccount()) {
201
- this.setActiveAccount(accountName);
202
- }
203
-
204
- await this.keychainManager.removePrivateKey(accountName);
205
-
206
- return wallet.privateKey;
207
- }
208
-
209
- protected async promptPassword(message: string): Promise<string> {
210
- const answer = await inquirer.prompt([
211
- {
212
- type: "password",
213
- name: "password",
214
- message: chalk.yellow(message),
215
- mask: "*",
216
- validate: (input: string) => {
217
- if (!input) {
218
- return "Password cannot be empty";
219
- }
220
- return true;
221
- },
222
- },
223
- ]);
224
- return answer.password;
225
- }
226
-
227
- protected async confirmPrompt(message: string): Promise<void> {
228
- const answer = await inquirer.prompt([
229
- {
230
- type: "confirm",
231
- name: "confirmAction",
232
- message: chalk.yellow(message),
233
- default: true,
234
- },
235
- ]);
236
-
237
- if (!answer.confirmAction) {
238
- this.logError("Operation aborted!");
239
- process.exit(0);
240
- }
241
- }
242
-
243
- protected log(message: string, data?: any): void {
244
- console.log(chalk.white(`\n${message}`));
245
- if (data !== undefined) console.log(this.formatOutput(data));
246
- }
247
-
248
- protected logSuccess(message: string, data?: any): void {
249
- console.log(chalk.green(`\n✔ ${message}`));
250
- if (data !== undefined) console.log(chalk.green(this.formatOutput(data)));
251
- }
252
-
253
- protected logInfo(message: string, data?: any): void {
254
- console.log(chalk.blue(`\nℹ ${message}`));
255
- if (data !== undefined) console.log(chalk.blue(this.formatOutput(data)));
256
- }
257
-
258
- protected logWarning(message: string, data?: any): void {
259
- console.log(chalk.yellow(`\n⚠ ${message}`));
260
- if (data !== undefined) console.log(chalk.yellow(this.formatOutput(data)));
261
- }
262
-
263
- protected logError(message: string, error?: any): void {
264
- console.error(chalk.red(`\n✖ ${message}`));
265
- if (error !== undefined) console.error(chalk.red(this.formatOutput(error)));
266
- }
267
-
268
- protected startSpinner(message: string) {
269
- this.spinner.text = chalk.blue(`${message}`);
270
- this.spinner.start();
271
- }
272
-
273
- protected succeedSpinner(message: string, data?: any): void {
274
- if (data !== undefined) this.log("Result:", data);
275
- console.log('');
276
- this.spinner.succeed(chalk.green(message));
277
- }
278
-
279
- protected failSpinner(message: string, error?: any, shouldExit = true): void {
280
- if (error) this.log("Error:", error);
281
- console.log("");
282
- this.spinner.fail(chalk.red(message));
283
- if (shouldExit) {
284
- process.exit(1);
285
- }
286
- }
287
-
288
- protected stopSpinner(): void {
289
- this.spinner.stop();
290
- }
291
-
292
- protected setSpinnerText(message: string): void {
293
- this.spinner.text = chalk.blue(message);
294
- }
295
- }
@@ -1,41 +0,0 @@
1
- import fetch from "node-fetch";
2
- import {v4 as uuidv4} from "uuid";
3
-
4
- import {DEFAULT_JSON_RPC_URL} from "../config/simulator";
5
-
6
- export interface JsonRPCParams {
7
- method: string;
8
- params: any[];
9
- }
10
-
11
- export class JsonRpcClient {
12
- serverUrl: string;
13
-
14
- constructor(serverUrl: string) {
15
- this.serverUrl = serverUrl;
16
- }
17
-
18
- async request({method, params}: JsonRPCParams): Promise<any | null> {
19
- const response = await fetch(this.serverUrl, {
20
- method: "POST",
21
- headers: {
22
- "Content-Type": "application/json",
23
- },
24
- body: JSON.stringify({
25
- jsonrpc: "2.0",
26
- id: uuidv4(),
27
- method,
28
- params,
29
- }),
30
- });
31
-
32
- if (response.ok) {
33
- return response.json();
34
- }
35
- const result = await response.json();
36
-
37
- throw new Error(result?.error?.message || response.statusText);
38
-
39
- }
40
- }
41
- export const rpcClient = new JsonRpcClient(DEFAULT_JSON_RPC_URL);