genlayer 0.18.5 → 0.19.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.19.0 (2025-07-09)
4
+
5
+ ### Features
6
+
7
+ * appeal command ([#233](https://github.com/yeagerai/genlayer-cli/issues/233)) ([a33f882](https://github.com/yeagerai/genlayer-cli/commit/a33f882ec7f1e7758bbf6daef67b425be10e87f2))
8
+
3
9
  ## 0.18.5 (2025-07-09)
4
10
 
5
11
  ## 0.18.4 (2025-06-27)
package/dist/index.js CHANGED
@@ -17723,7 +17723,7 @@ var require_semver2 = __commonJS({
17723
17723
  import { program } from "commander";
17724
17724
 
17725
17725
  // package.json
17726
- var version = "0.18.5";
17726
+ var version = "0.19.0";
17727
17727
  var package_default = {
17728
17728
  name: "genlayer",
17729
17729
  version,
@@ -42779,6 +42779,43 @@ function initializeNetworkCommands(program2) {
42779
42779
  return program2;
42780
42780
  }
42781
42781
 
42782
+ // src/commands/transactions/appeal.ts
42783
+ var AppealAction = class extends BaseAction {
42784
+ constructor() {
42785
+ super();
42786
+ }
42787
+ async appeal({
42788
+ txId,
42789
+ rpc
42790
+ }) {
42791
+ const client = await this.getClient(rpc);
42792
+ await client.initializeConsensusSmartContract();
42793
+ this.startSpinner(`Appealing transaction ${txId}...`);
42794
+ try {
42795
+ const hash2 = await client.appealTransaction({
42796
+ txId
42797
+ });
42798
+ const result = await client.waitForTransactionReceipt({
42799
+ hash: hash2,
42800
+ retries: 100,
42801
+ interval: 5e3
42802
+ });
42803
+ this.succeedSpinner("Appeal operation successfully executed", result);
42804
+ } catch (error) {
42805
+ this.failSpinner("Error during appeal operation", error);
42806
+ }
42807
+ }
42808
+ };
42809
+
42810
+ // src/commands/transactions/index.ts
42811
+ function initializeTransactionsCommands(program2) {
42812
+ program2.command("appeal <txId>").description("Appeal a transaction by its hash").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (txId, options) => {
42813
+ const appealAction = new AppealAction();
42814
+ await appealAction.appeal({ txId, ...options });
42815
+ });
42816
+ return program2;
42817
+ }
42818
+
42782
42819
  // src/index.ts
42783
42820
  function initializeCLI() {
42784
42821
  program.version(version).description(CLI_DESCRIPTION);
@@ -42790,6 +42827,7 @@ function initializeCLI() {
42790
42827
  initializeValidatorCommands(program);
42791
42828
  initializeScaffoldCommands(program);
42792
42829
  initializeNetworkCommands(program);
42830
+ initializeTransactionsCommands(program);
42793
42831
  program.parse(process.argv);
42794
42832
  }
42795
42833
  initializeCLI();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genlayer",
3
- "version": "0.18.5",
3
+ "version": "0.19.0",
4
4
  "description": "GenLayer Command Line Tool",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -0,0 +1,39 @@
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
+ }
@@ -0,0 +1,16 @@
1
+ import {Command} from "commander";
2
+ import {TransactionHash} from "genlayer-js/types";
3
+ import {AppealAction, AppealOptions} from "./appeal";
4
+
5
+ export function initializeTransactionsCommands(program: Command) {
6
+ program
7
+ .command("appeal <txId>")
8
+ .description("Appeal a transaction by its hash")
9
+ .option("--rpc <rpcUrl>", "RPC URL for the network")
10
+ .action(async (txId: TransactionHash, options: AppealOptions) => {
11
+ const appealAction = new AppealAction();
12
+ await appealAction.appeal({txId, ...options});
13
+ });
14
+
15
+ return program;
16
+ }
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ import {initializeValidatorCommands} from "../src/commands/validators";
10
10
  import {initializeUpdateCommands} from "../src/commands/update";
11
11
  import {initializeScaffoldCommands} from "../src/commands/scaffold";
12
12
  import {initializeNetworkCommands} from "../src/commands/network";
13
+ import {initializeTransactionsCommands} from "../src/commands/transactions";
13
14
 
14
15
  export function initializeCLI() {
15
16
  program.version(version).description(CLI_DESCRIPTION);
@@ -21,6 +22,7 @@ export function initializeCLI() {
21
22
  initializeValidatorCommands(program);
22
23
  initializeScaffoldCommands(program);
23
24
  initializeNetworkCommands(program);
25
+ initializeTransactionsCommands(program);
24
26
  program.parse(process.argv);
25
27
  }
26
28
 
@@ -0,0 +1,99 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import {createClient, createAccount} from "genlayer-js";
3
+ import type {TransactionHash} from "genlayer-js/types";
4
+ import {AppealAction} from "../../src/commands/transactions/appeal";
5
+
6
+ vi.mock("genlayer-js");
7
+
8
+ describe("AppealAction", () => {
9
+ let appealAction: AppealAction;
10
+ const mockClient = {
11
+ appealTransaction: vi.fn(),
12
+ waitForTransactionReceipt: vi.fn(),
13
+ initializeConsensusSmartContract: vi.fn(),
14
+ };
15
+
16
+ const mockPrivateKey = "mocked_private_key";
17
+ const mockTxId = "0x1234567890123456789012345678901234567890123456789012345678901234" as TransactionHash;
18
+
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ vi.mocked(createClient).mockReturnValue(mockClient as any);
22
+ vi.mocked(createAccount).mockReturnValue({privateKey: mockPrivateKey} as any);
23
+ appealAction = new AppealAction();
24
+ vi.spyOn(appealAction as any, "getPrivateKey").mockResolvedValue(mockPrivateKey);
25
+
26
+ vi.spyOn(appealAction as any, "startSpinner").mockImplementation(() => {});
27
+ vi.spyOn(appealAction as any, "succeedSpinner").mockImplementation(() => {});
28
+ vi.spyOn(appealAction as any, "failSpinner").mockImplementation(() => {});
29
+ });
30
+
31
+ afterEach(() => {
32
+ vi.restoreAllMocks();
33
+ });
34
+
35
+ test("calls appealTransaction successfully", async () => {
36
+ const mockReceipt = {status: "success"};
37
+
38
+ vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
39
+
40
+ await appealAction.appeal({
41
+ txId: mockTxId,
42
+ });
43
+
44
+ expect(mockClient.appealTransaction).toHaveBeenCalledWith({
45
+ txId: mockTxId,
46
+ });
47
+ expect(appealAction["succeedSpinner"]).toHaveBeenCalledWith(
48
+ "Appeal operation successfully executed",
49
+ mockReceipt,
50
+ );
51
+ });
52
+
53
+ test("handles appealTransaction errors", async () => {
54
+ vi.mocked(mockClient.appealTransaction).mockRejectedValue(new Error("Mocked appeal error"));
55
+
56
+ await appealAction.appeal({txId: mockTxId});
57
+
58
+ expect(appealAction["failSpinner"]).toHaveBeenCalledWith(
59
+ "Error during appeal operation",
60
+ expect.any(Error),
61
+ );
62
+ });
63
+
64
+ test("uses custom RPC URL for appeal operations", async () => {
65
+ const rpcUrl = "https://custom-rpc-url.com";
66
+ const mockReceipt = {status: "success"};
67
+
68
+ vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
69
+
70
+ await appealAction.appeal({
71
+ txId: mockTxId,
72
+ rpc: rpcUrl,
73
+ });
74
+
75
+ expect(createClient).toHaveBeenCalledWith(
76
+ expect.objectContaining({
77
+ endpoint: rpcUrl,
78
+ }),
79
+ );
80
+ expect(mockClient.appealTransaction).toHaveBeenCalledWith({
81
+ txId: mockTxId,
82
+ });
83
+ expect(appealAction["succeedSpinner"]).toHaveBeenCalledWith(
84
+ "Appeal operation successfully executed",
85
+ mockReceipt,
86
+ );
87
+ });
88
+
89
+ test("initializes consensus smart contract before appeal", async () => {
90
+ const mockReceipt = {status: "success"};
91
+
92
+ vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
93
+
94
+ await appealAction.appeal({txId: mockTxId});
95
+
96
+ expect(mockClient.initializeConsensusSmartContract).toHaveBeenCalledTimes(1);
97
+ expect(mockClient.appealTransaction).toHaveBeenCalled();
98
+ });
99
+ });
@@ -0,0 +1,58 @@
1
+ import {Command} from "commander";
2
+ import {AppealAction} from "../../src/commands/transactions/appeal";
3
+ import {vi, describe, beforeEach, afterEach, test, expect} from "vitest";
4
+ import {initializeTransactionsCommands} from "../../src/commands/transactions";
5
+
6
+ vi.mock("../../src/commands/transactions/appeal");
7
+
8
+ describe("appeal command", () => {
9
+ let program: Command;
10
+ const mockTxId = "0x1234567890123456789012345678901234567890123456789012345678901234";
11
+
12
+ beforeEach(() => {
13
+ program = new Command();
14
+ initializeTransactionsCommands(program);
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ afterEach(() => {
19
+ vi.restoreAllMocks();
20
+ });
21
+
22
+ test("AppealAction.appeal is called with default options", async () => {
23
+ program.parse(["node", "test", "appeal", mockTxId]);
24
+ expect(AppealAction).toHaveBeenCalledTimes(1);
25
+ expect(AppealAction.prototype.appeal).toHaveBeenCalledWith({
26
+ txId: mockTxId,
27
+ });
28
+ });
29
+
30
+ test("AppealAction.appeal is called with custom RPC URL", async () => {
31
+ program.parse([
32
+ "node",
33
+ "test",
34
+ "appeal",
35
+ mockTxId,
36
+ "--rpc",
37
+ "https://custom-rpc-url-for-appeal.com",
38
+ ]);
39
+ expect(AppealAction).toHaveBeenCalledTimes(1);
40
+ expect(AppealAction.prototype.appeal).toHaveBeenCalledWith({
41
+ txId: mockTxId,
42
+ rpc: "https://custom-rpc-url-for-appeal.com",
43
+ });
44
+ });
45
+
46
+ test("AppealAction is instantiated when the appeal command is executed", async () => {
47
+ program.parse(["node", "test", "appeal", mockTxId]);
48
+ expect(AppealAction).toHaveBeenCalledTimes(1);
49
+ });
50
+
51
+ test("throws error for unrecognized options", async () => {
52
+ const appealCommand = program.commands.find(cmd => cmd.name() === "appeal");
53
+ appealCommand?.exitOverride();
54
+ expect(() =>
55
+ program.parse(["node", "test", "appeal", mockTxId, "--invalid-option"]),
56
+ ).toThrowError("error: unknown option '--invalid-option'");
57
+ });
58
+ });
@@ -41,6 +41,10 @@ vi.mock("../src/commands/network", () => ({
41
41
  initializeNetworkCommands: vi.fn(),
42
42
  }));
43
43
 
44
+ vi.mock("../src/commands/transactions", () => ({
45
+ initializeTransactionsCommands: vi.fn(),
46
+ }));
47
+
44
48
  describe("CLI", () => {
45
49
  it("should initialize CLI", () => {
46
50
  expect(initializeCLI).not.toThrow();