genlayer 0.25.0 → 0.26.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.26.0 (2025-08-07)
4
+
5
+ ### Features
6
+
7
+ * add schema command to inspect deployed contract schema ([#244](https://github.com/yeagerai/genlayer-cli/issues/244)) ([4d66a7b](https://github.com/yeagerai/genlayer-cli/commit/4d66a7b9b2ac813cf0d47f12fc82cbc06ed25b3c))
8
+
3
9
  ## 0.25.0 (2025-07-23)
4
10
 
5
11
  ### Features
package/README.md CHANGED
@@ -146,6 +146,7 @@ USAGE:
146
146
  genlayer deploy [options]
147
147
  genlayer call <contractAddress> <method> [options]
148
148
  genlayer write <contractAddress> <method> [options]
149
+ genlayer schema <contractAddress> [options]
149
150
 
150
151
  OPTIONS (deploy):
151
152
  --contract <contractPath> (Optional) Path to the intelligent contract to deploy
@@ -160,12 +161,16 @@ OPTIONS (write):
160
161
  --rpc <rpcUrl> RPC URL for the network
161
162
  --args <args...> Positional arguments for the method (space-separated, use quotes for multi-word arguments)
162
163
 
164
+ OPTIONS (schema):
165
+ --rpc <rpcUrl> RPC URL for the network
166
+
163
167
  EXAMPLES:
164
168
  genlayer deploy
165
169
  genlayer deploy --contract ./my_contract.gpy
166
170
  genlayer deploy --contract ./my_contract.gpy --args "arg1" "arg2" 123
167
171
  genlayer call 0x123456789abcdef greet --args "Hello World!"
168
172
  genlayer write 0x123456789abcdef updateValue --args 42
173
+ genlayer schema 0x123456789abcdef
169
174
  ```
170
175
 
171
176
  ##### Deploy Behavior
@@ -176,6 +181,9 @@ EXAMPLES:
176
181
  - `call` - Calls a contract method without sending a transaction or changing the state (read-only)
177
182
  - `write` - Sends a transaction to a contract method that modifies the state
178
183
 
184
+ ##### Schema
185
+ - `schema` - Retrieves the contract schema
186
+
179
187
  #### Keypair Management
180
188
 
181
189
  Generate and manage keypairs.
package/dist/index.js CHANGED
@@ -17856,7 +17856,7 @@ var require_semver2 = __commonJS({
17856
17856
  import { program } from "commander";
17857
17857
 
17858
17858
  // package.json
17859
- var version = "0.25.0";
17859
+ var version = "0.26.0";
17860
17860
  var package_default = {
17861
17861
  name: "genlayer",
17862
17862
  version,
@@ -42553,6 +42553,27 @@ var WriteAction = class extends BaseAction {
42553
42553
  }
42554
42554
  };
42555
42555
 
42556
+ // src/commands/contracts/schema.ts
42557
+ var SchemaAction = class extends BaseAction {
42558
+ constructor() {
42559
+ super();
42560
+ }
42561
+ async schema({
42562
+ contractAddress,
42563
+ rpc
42564
+ }) {
42565
+ const client = await this.getClient(rpc, true);
42566
+ await client.initializeConsensusSmartContract();
42567
+ this.startSpinner(`Getting schema for contract at ${contractAddress}...`);
42568
+ try {
42569
+ const result = await client.getContractSchema(contractAddress);
42570
+ this.succeedSpinner("Contract schema retrieved successfully", result);
42571
+ } catch (error) {
42572
+ this.failSpinner("Error retrieving contract schema", error);
42573
+ }
42574
+ }
42575
+ };
42576
+
42556
42577
  // src/commands/contracts/index.ts
42557
42578
  function parseArg(value, previous = []) {
42558
42579
  if (value === "true") return [...previous, true];
@@ -42581,8 +42602,8 @@ function initializeContractsCommands(program2) {
42581
42602
  parseArg,
42582
42603
  []
42583
42604
  ).action(async (contractAddress, method, options) => {
42584
- const caller = new CallAction();
42585
- await caller.call({ contractAddress, method, ...options });
42605
+ const callAction = new CallAction();
42606
+ await callAction.call({ contractAddress, method, ...options });
42586
42607
  });
42587
42608
  program2.command("write <contractAddress> <method>").description("Sends a transaction to a contract method that modifies the state").option("--rpc <rpcUrl>", "RPC URL for the network").option(
42588
42609
  "--args <args...>",
@@ -42590,8 +42611,12 @@ function initializeContractsCommands(program2) {
42590
42611
  parseArg,
42591
42612
  []
42592
42613
  ).action(async (contractAddress, method, options) => {
42593
- const writer = new WriteAction();
42594
- await writer.write({ contractAddress, method, ...options });
42614
+ const writeAction = new WriteAction();
42615
+ await writeAction.write({ contractAddress, method, ...options });
42616
+ });
42617
+ program2.command("schema <contractAddress>").description("Get the schema for a deployed contract").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (contractAddress, options) => {
42618
+ const schemaAction = new SchemaAction();
42619
+ await schemaAction.schema({ contractAddress, ...options });
42595
42620
  });
42596
42621
  return program2;
42597
42622
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genlayer",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "GenLayer Command Line Tool",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -2,6 +2,7 @@ import {Command} from "commander";
2
2
  import {DeployAction, DeployOptions, DeployScriptsOptions} from "./deploy";
3
3
  import {CallAction, CallOptions} from "./call";
4
4
  import {WriteAction, WriteOptions} from "./write";
5
+ import {SchemaAction, SchemaOptions} from "./schema";
5
6
 
6
7
  function parseArg(value: string, previous: any[] = []): any[] {
7
8
  if (value === "true") return [...previous, true];
@@ -43,8 +44,8 @@ export function initializeContractsCommands(program: Command) {
43
44
  [],
44
45
  )
45
46
  .action(async (contractAddress: string, method: string, options: CallOptions) => {
46
- const caller = new CallAction();
47
- await caller.call({contractAddress, method, ...options});
47
+ const callAction = new CallAction();
48
+ await callAction.call({contractAddress, method, ...options});
48
49
  });
49
50
 
50
51
  program
@@ -58,8 +59,17 @@ export function initializeContractsCommands(program: Command) {
58
59
  [],
59
60
  )
60
61
  .action(async (contractAddress: string, method: string, options: WriteOptions) => {
61
- const writer = new WriteAction();
62
- await writer.write({contractAddress, method, ...options});
62
+ const writeAction = new WriteAction();
63
+ await writeAction.write({contractAddress, method, ...options});
64
+ });
65
+
66
+ program
67
+ .command("schema <contractAddress>")
68
+ .description("Get the schema for a deployed contract")
69
+ .option("--rpc <rpcUrl>", "RPC URL for the network")
70
+ .action(async (contractAddress: string, options: SchemaOptions) => {
71
+ const schemaAction = new SchemaAction();
72
+ await schemaAction.schema({contractAddress, ...options});
63
73
  });
64
74
 
65
75
  return program;
@@ -0,0 +1,31 @@
1
+ import {BaseAction} from "../../lib/actions/BaseAction";
2
+ import type {Address} from "genlayer-js/types";
3
+
4
+ export interface SchemaOptions {
5
+ rpc?: string;
6
+ }
7
+
8
+ export class SchemaAction extends BaseAction {
9
+ constructor() {
10
+ super();
11
+ }
12
+
13
+ async schema({
14
+ contractAddress,
15
+ rpc,
16
+ }: {
17
+ contractAddress: string;
18
+ rpc?: string;
19
+ }): Promise<void> {
20
+ const client = await this.getClient(rpc, true);
21
+ await client.initializeConsensusSmartContract();
22
+ this.startSpinner(`Getting schema for contract at ${contractAddress}...`);
23
+
24
+ try {
25
+ const result = await client.getContractSchema(contractAddress as Address);
26
+ this.succeedSpinner("Contract schema retrieved successfully", result);
27
+ } catch (error) {
28
+ this.failSpinner("Error retrieving contract schema", error);
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,94 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import {createClient, createAccount} from "genlayer-js";
3
+ import {SchemaAction} from "../../src/commands/contracts/schema";
4
+
5
+ vi.mock("genlayer-js");
6
+
7
+ describe("SchemaAction", () => {
8
+ let schemaAction: SchemaAction;
9
+ const mockClient = {
10
+ getContractSchema: vi.fn(),
11
+ initializeConsensusSmartContract: vi.fn(),
12
+ };
13
+
14
+ const mockPrivateKey = "mocked_private_key";
15
+
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+ vi.mocked(createClient).mockReturnValue(mockClient as any);
19
+ vi.mocked(createAccount).mockReturnValue({privateKey: mockPrivateKey} as any);
20
+ schemaAction = new SchemaAction();
21
+ vi.spyOn(schemaAction as any, "getAccount").mockResolvedValue({privateKey: mockPrivateKey});
22
+
23
+ vi.spyOn(schemaAction as any, "startSpinner").mockImplementation(() => {});
24
+ vi.spyOn(schemaAction as any, "succeedSpinner").mockImplementation(() => {});
25
+ vi.spyOn(schemaAction as any, "failSpinner").mockImplementation(() => {});
26
+ vi.spyOn(schemaAction as any, "log").mockImplementation(() => {});
27
+ });
28
+
29
+ afterEach(() => {
30
+ vi.restoreAllMocks();
31
+ });
32
+
33
+ test("gets contract schema successfully", async () => {
34
+ const mockResult = {
35
+ methods: {
36
+ getData: {
37
+ params: [["value", "int"]],
38
+ ret: "int",
39
+ readonly: true,
40
+ },
41
+ },
42
+ };
43
+
44
+ vi.mocked(mockClient.getContractSchema).mockResolvedValue(mockResult);
45
+
46
+ await schemaAction.schema({
47
+ contractAddress: "0xMockedContract",
48
+ });
49
+
50
+ expect(mockClient.getContractSchema).toHaveBeenCalledWith("0xMockedContract");
51
+ expect(schemaAction["succeedSpinner"]).toHaveBeenCalledWith(
52
+ "Contract schema retrieved successfully",
53
+ mockResult,
54
+ );
55
+ });
56
+
57
+ test("handles getContractSchema errors", async () => {
58
+ vi.mocked(mockClient.getContractSchema).mockRejectedValue(new Error("Mocked schema error"));
59
+
60
+ await schemaAction.schema({contractAddress: "0xMockedContract"});
61
+
62
+ expect(schemaAction["failSpinner"]).toHaveBeenCalledWith("Error retrieving contract schema", expect.any(Error));
63
+ });
64
+
65
+ test("uses custom RPC URL when provided", async () => {
66
+ const mockResult = {methods: {}};
67
+ vi.mocked(mockClient.getContractSchema).mockResolvedValue(mockResult);
68
+
69
+ await schemaAction.schema({
70
+ contractAddress: "0xMockedContract",
71
+ rpc: "https://custom-rpc-url.com",
72
+ });
73
+
74
+ expect(createClient).toHaveBeenCalledWith(
75
+ expect.objectContaining({
76
+ endpoint: "https://custom-rpc-url.com",
77
+ }),
78
+ );
79
+ expect(mockClient.getContractSchema).toHaveBeenCalledWith("0xMockedContract");
80
+ expect(schemaAction["succeedSpinner"]).toHaveBeenCalledWith(
81
+ "Contract schema retrieved successfully",
82
+ mockResult,
83
+ );
84
+ });
85
+
86
+ test("initializes consensus smart contract", async () => {
87
+ const mockResult = {methods: {}};
88
+ vi.mocked(mockClient.getContractSchema).mockResolvedValue(mockResult);
89
+
90
+ await schemaAction.schema({contractAddress: "0xMockedContract"});
91
+
92
+ expect(mockClient.initializeConsensusSmartContract).toHaveBeenCalled();
93
+ });
94
+ });
@@ -0,0 +1,67 @@
1
+ import { Command } from "commander";
2
+ import { SchemaAction } from "../../src/commands/contracts/schema";
3
+ import { vi, describe, beforeEach, afterEach, test, expect } from "vitest";
4
+ import { initializeContractsCommands } from "../../src/commands/contracts";
5
+
6
+ vi.mock("../../src/commands/contracts/schema");
7
+ vi.mock("esbuild", () => ({
8
+ buildSync: vi.fn(),
9
+ }));
10
+
11
+ describe("schema command", () => {
12
+ let program: Command;
13
+
14
+ beforeEach(() => {
15
+ program = new Command();
16
+ initializeContractsCommands(program);
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ afterEach(() => {
21
+ vi.restoreAllMocks();
22
+ });
23
+
24
+ test("SchemaAction.schema is called with default options", async () => {
25
+ program.parse(["node", "test", "schema", "0xMockedContract"]);
26
+ expect(SchemaAction).toHaveBeenCalledTimes(1);
27
+ expect(SchemaAction.prototype.schema).toHaveBeenCalledWith({
28
+ contractAddress: "0xMockedContract",
29
+ });
30
+ });
31
+
32
+ test("SchemaAction.schema is called with custom RPC URL", async () => {
33
+ program.parse([
34
+ "node",
35
+ "test",
36
+ "schema",
37
+ "0xMockedContract",
38
+ "--rpc",
39
+ "https://custom-rpc-url.com"
40
+ ]);
41
+ expect(SchemaAction).toHaveBeenCalledTimes(1);
42
+ expect(SchemaAction.prototype.schema).toHaveBeenCalledWith({
43
+ contractAddress: "0xMockedContract",
44
+ rpc: "https://custom-rpc-url.com"
45
+ });
46
+ });
47
+
48
+ test("SchemaAction is instantiated when the schema command is executed", async () => {
49
+ program.parse(["node", "test", "schema", "0xMockedContract"]);
50
+ expect(SchemaAction).toHaveBeenCalledTimes(1);
51
+ });
52
+
53
+ test("throws error for unrecognized options", async () => {
54
+ const schemaCommand = program.commands.find((cmd) => cmd.name() === "schema");
55
+ schemaCommand?.exitOverride();
56
+ expect(() => program.parse(["node", "test", "schema", "0xMockedContract", "--unknown"]))
57
+ .toThrowError("error: unknown option '--unknown'");
58
+ });
59
+
60
+ test("SchemaAction.schema is called without throwing errors for valid options", async () => {
61
+ program.parse(["node", "test", "schema", "0xMockedContract"]);
62
+ vi.mocked(SchemaAction.prototype.schema).mockResolvedValueOnce(undefined);
63
+ expect(() =>
64
+ program.parse(["node", "test", "schema", "0xMockedContract"])
65
+ ).not.toThrow();
66
+ });
67
+ });