genlayer 0.38.8 → 0.38.10

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 (205) hide show
  1. package/.eslintignore +2 -0
  2. package/.github/workflows/cli-docs.yml +124 -0
  3. package/.github/workflows/publish.yml +55 -0
  4. package/.github/workflows/smoke.yml +27 -0
  5. package/.github/workflows/validate-code.yml +51 -0
  6. package/.prettierignore +19 -0
  7. package/.prettierrc +12 -0
  8. package/.release-it.json +66 -0
  9. package/CHANGELOG.md +545 -0
  10. package/CLAUDE.md +55 -0
  11. package/CONTRIBUTING.md +117 -0
  12. package/dist/index.js +221 -62
  13. package/docs/api-references/_meta.json +9 -0
  14. package/docs/api-references/accounts/_meta.json +3 -0
  15. package/docs/api-references/accounts/account/create.mdx +19 -0
  16. package/docs/api-references/accounts/account/export.mdx +19 -0
  17. package/docs/api-references/accounts/account/import.mdx +22 -0
  18. package/docs/api-references/accounts/account/list.mdx +15 -0
  19. package/docs/api-references/accounts/account/lock.mdx +16 -0
  20. package/docs/api-references/accounts/account/remove.mdx +20 -0
  21. package/docs/api-references/accounts/account/send.mdx +24 -0
  22. package/docs/api-references/accounts/account/show.mdx +17 -0
  23. package/docs/api-references/accounts/account/unlock.mdx +17 -0
  24. package/docs/api-references/accounts/account/use.mdx +19 -0
  25. package/docs/api-references/accounts/account.mdx +32 -0
  26. package/docs/api-references/configuration/_meta.json +4 -0
  27. package/docs/api-references/configuration/config/get.mdx +21 -0
  28. package/docs/api-references/configuration/config/reset.mdx +21 -0
  29. package/docs/api-references/configuration/config/set.mdx +21 -0
  30. package/docs/api-references/configuration/config.mdx +25 -0
  31. package/docs/api-references/configuration/network/info.mdx +15 -0
  32. package/docs/api-references/configuration/network/list.mdx +15 -0
  33. package/docs/api-references/configuration/network/set.mdx +21 -0
  34. package/docs/api-references/configuration/network.mdx +25 -0
  35. package/docs/api-references/contracts/_meta.json +7 -0
  36. package/docs/api-references/contracts/call.mdx +21 -0
  37. package/docs/api-references/contracts/code.mdx +20 -0
  38. package/docs/api-references/contracts/deploy.mdx +17 -0
  39. package/docs/api-references/contracts/schema.mdx +20 -0
  40. package/docs/api-references/contracts/write.mdx +21 -0
  41. package/docs/api-references/environment/_meta.json +7 -0
  42. package/docs/api-references/environment/init.mdx +20 -0
  43. package/docs/api-references/environment/new.mdx +21 -0
  44. package/docs/api-references/environment/stop.mdx +15 -0
  45. package/docs/api-references/environment/up.mdx +20 -0
  46. package/docs/api-references/environment/update/ollama.mdx +16 -0
  47. package/docs/api-references/environment/update.mdx +23 -0
  48. package/docs/api-references/index.mdx +35 -0
  49. package/docs/api-references/localnet/_meta.json +3 -0
  50. package/docs/api-references/localnet/localnet/validators/count.mdx +15 -0
  51. package/docs/api-references/localnet/localnet/validators/create-random.mdx +16 -0
  52. package/docs/api-references/localnet/localnet/validators/create.mdx +19 -0
  53. package/docs/api-references/localnet/localnet/validators/delete.mdx +16 -0
  54. package/docs/api-references/localnet/localnet/validators/get.mdx +16 -0
  55. package/docs/api-references/localnet/localnet/validators/update.mdx +23 -0
  56. package/docs/api-references/localnet/localnet/validators.mdx +28 -0
  57. package/docs/api-references/localnet/localnet.mdx +23 -0
  58. package/docs/api-references/staking/_meta.json +3 -0
  59. package/docs/api-references/staking/staking/active-validators.mdx +18 -0
  60. package/docs/api-references/staking/staking/banned-validators.mdx +18 -0
  61. package/docs/api-references/staking/staking/delegation-info.mdx +25 -0
  62. package/docs/api-references/staking/staking/delegator-claim.mdx +26 -0
  63. package/docs/api-references/staking/staking/delegator-exit.mdx +26 -0
  64. package/docs/api-references/staking/staking/delegator-join.mdx +26 -0
  65. package/docs/api-references/staking/staking/epoch-info.mdx +19 -0
  66. package/docs/api-references/staking/staking/prime-all.mdx +20 -0
  67. package/docs/api-references/staking/staking/quarantined-validators.mdx +18 -0
  68. package/docs/api-references/staking/staking/set-identity.mdx +33 -0
  69. package/docs/api-references/staking/staking/set-operator.mdx +26 -0
  70. package/docs/api-references/staking/staking/validator-claim.mdx +24 -0
  71. package/docs/api-references/staking/staking/validator-deposit.mdx +25 -0
  72. package/docs/api-references/staking/staking/validator-exit.mdx +25 -0
  73. package/docs/api-references/staking/staking/validator-history.mdx +29 -0
  74. package/docs/api-references/staking/staking/validator-info.mdx +25 -0
  75. package/docs/api-references/staking/staking/validator-join.mdx +22 -0
  76. package/docs/api-references/staking/staking/validator-prime.mdx +25 -0
  77. package/docs/api-references/staking/staking/validators.mdx +19 -0
  78. package/docs/api-references/staking/staking/wizard.mdx +20 -0
  79. package/docs/api-references/staking/staking.mdx +42 -0
  80. package/docs/api-references/transactions/_meta.json +6 -0
  81. package/docs/api-references/transactions/appeal-bond.mdx +20 -0
  82. package/docs/api-references/transactions/appeal.mdx +21 -0
  83. package/docs/api-references/transactions/receipt.mdx +25 -0
  84. package/docs/api-references/transactions/trace.mdx +21 -0
  85. package/docs/delegator-guide.md +203 -0
  86. package/docs/validator-guide.md +329 -0
  87. package/esbuild.config.dev.js +17 -0
  88. package/esbuild.config.js +22 -0
  89. package/esbuild.config.prod.js +17 -0
  90. package/eslint.config.js +60 -0
  91. package/package.json +2 -11
  92. package/renovate.json +22 -0
  93. package/scripts/generate-cli-docs.mjs +68 -5
  94. package/src/commands/account/create.ts +30 -0
  95. package/src/commands/account/export.ts +106 -0
  96. package/src/commands/account/import.ts +135 -0
  97. package/src/commands/account/index.ts +129 -0
  98. package/src/commands/account/list.ts +34 -0
  99. package/src/commands/account/lock.ts +39 -0
  100. package/src/commands/account/remove.ts +30 -0
  101. package/src/commands/account/send.ts +162 -0
  102. package/src/commands/account/show.ts +74 -0
  103. package/src/commands/account/unlock.ts +56 -0
  104. package/src/commands/account/use.ts +21 -0
  105. package/src/commands/config/getSetReset.ts +51 -0
  106. package/src/commands/config/index.ts +30 -0
  107. package/src/commands/contracts/call.ts +39 -0
  108. package/src/commands/contracts/code.ts +33 -0
  109. package/src/commands/contracts/deploy.ts +161 -0
  110. package/src/commands/contracts/index.ts +150 -0
  111. package/src/commands/contracts/schema.ts +31 -0
  112. package/src/commands/contracts/write.ts +49 -0
  113. package/src/commands/general/index.ts +45 -0
  114. package/src/commands/general/init.ts +180 -0
  115. package/src/commands/general/start.ts +128 -0
  116. package/src/commands/general/stop.ts +26 -0
  117. package/src/commands/localnet/index.ts +100 -0
  118. package/src/commands/localnet/validators.ts +269 -0
  119. package/src/commands/network/index.ts +29 -0
  120. package/src/commands/network/setNetwork.ts +77 -0
  121. package/src/commands/scaffold/index.ts +16 -0
  122. package/src/commands/scaffold/new.ts +34 -0
  123. package/src/commands/staking/StakingAction.ts +279 -0
  124. package/src/commands/staking/delegatorClaim.ts +41 -0
  125. package/src/commands/staking/delegatorExit.ts +56 -0
  126. package/src/commands/staking/delegatorJoin.ts +44 -0
  127. package/src/commands/staking/index.ts +357 -0
  128. package/src/commands/staking/setIdentity.ts +78 -0
  129. package/src/commands/staking/setOperator.ts +46 -0
  130. package/src/commands/staking/stakingInfo.ts +584 -0
  131. package/src/commands/staking/validatorClaim.ts +43 -0
  132. package/src/commands/staking/validatorDeposit.ts +48 -0
  133. package/src/commands/staking/validatorExit.ts +63 -0
  134. package/src/commands/staking/validatorHistory.ts +300 -0
  135. package/src/commands/staking/validatorJoin.ts +47 -0
  136. package/src/commands/staking/validatorPrime.ts +73 -0
  137. package/src/commands/staking/wizard.ts +809 -0
  138. package/src/commands/transactions/appeal.ts +83 -0
  139. package/src/commands/transactions/index.ts +60 -0
  140. package/src/commands/transactions/receipt.ts +90 -0
  141. package/src/commands/transactions/trace.ts +42 -0
  142. package/src/commands/update/index.ts +25 -0
  143. package/src/commands/update/ollama.ts +103 -0
  144. package/src/lib/actions/BaseAction.ts +301 -0
  145. package/src/lib/clients/jsonRpcClient.ts +41 -0
  146. package/src/lib/clients/system.ts +73 -0
  147. package/src/lib/config/ConfigFileManager.ts +194 -0
  148. package/src/lib/config/KeychainManager.ts +89 -0
  149. package/src/lib/config/simulator.ts +68 -0
  150. package/src/lib/config/text.ts +2 -0
  151. package/src/lib/errors/missingRequirement.ts +9 -0
  152. package/src/lib/errors/versionRequired.ts +9 -0
  153. package/src/lib/interfaces/ISimulatorService.ts +39 -0
  154. package/src/lib/services/simulator.ts +386 -0
  155. package/src/types/node-fetch.d.ts +1 -0
  156. package/tests/actions/appeal.test.ts +141 -0
  157. package/tests/actions/call.test.ts +94 -0
  158. package/tests/actions/code.test.ts +87 -0
  159. package/tests/actions/create.test.ts +65 -0
  160. package/tests/actions/deploy.test.ts +420 -0
  161. package/tests/actions/getSetReset.test.ts +88 -0
  162. package/tests/actions/init.test.ts +483 -0
  163. package/tests/actions/lock.test.ts +86 -0
  164. package/tests/actions/new.test.ts +80 -0
  165. package/tests/actions/ollama.test.ts +193 -0
  166. package/tests/actions/receipt.test.ts +261 -0
  167. package/tests/actions/schema.test.ts +94 -0
  168. package/tests/actions/setNetwork.test.ts +161 -0
  169. package/tests/actions/staking.test.ts +280 -0
  170. package/tests/actions/start.test.ts +257 -0
  171. package/tests/actions/stop.test.ts +77 -0
  172. package/tests/actions/unlock.test.ts +139 -0
  173. package/tests/actions/validators.test.ts +750 -0
  174. package/tests/actions/write.test.ts +102 -0
  175. package/tests/commands/account.test.ts +146 -0
  176. package/tests/commands/appeal.test.ts +97 -0
  177. package/tests/commands/call.test.ts +78 -0
  178. package/tests/commands/code.test.ts +69 -0
  179. package/tests/commands/config.test.ts +54 -0
  180. package/tests/commands/deploy.test.ts +83 -0
  181. package/tests/commands/init.test.ts +101 -0
  182. package/tests/commands/localnet.test.ts +131 -0
  183. package/tests/commands/network.test.ts +60 -0
  184. package/tests/commands/new.test.ts +68 -0
  185. package/tests/commands/parseArg.test.ts +156 -0
  186. package/tests/commands/receipt.test.ts +142 -0
  187. package/tests/commands/schema.test.ts +67 -0
  188. package/tests/commands/staking.test.ts +329 -0
  189. package/tests/commands/stop.test.ts +27 -0
  190. package/tests/commands/up.test.ts +105 -0
  191. package/tests/commands/update.test.ts +45 -0
  192. package/tests/commands/write.test.ts +76 -0
  193. package/tests/index.test.ts +56 -0
  194. package/tests/libs/baseAction.test.ts +535 -0
  195. package/tests/libs/configFileManager.test.ts +118 -0
  196. package/tests/libs/jsonRpcClient.test.ts +59 -0
  197. package/tests/libs/keychainManager.test.ts +156 -0
  198. package/tests/libs/platformCommands.test.ts +78 -0
  199. package/tests/libs/system.test.ts +148 -0
  200. package/tests/services/simulator.test.ts +789 -0
  201. package/tests/smoke.test.ts +134 -0
  202. package/tests/utils.ts +13 -0
  203. package/tsconfig.json +120 -0
  204. package/vitest.config.ts +13 -0
  205. package/vitest.smoke.config.ts +17 -0
@@ -0,0 +1,94 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import {createClient, createAccount} from "genlayer-js";
3
+ import {CallAction} from "../../src/commands/contracts/call";
4
+
5
+ vi.mock("genlayer-js");
6
+
7
+ describe("CallAction", () => {
8
+ let callActions: CallAction;
9
+ const mockClient = {
10
+ readContract: vi.fn(),
11
+ writeContract: vi.fn(),
12
+ waitForTransactionReceipt: vi.fn(),
13
+ getContractSchema: vi.fn(),
14
+ initializeConsensusSmartContract: vi.fn(),
15
+ };
16
+
17
+ const mockPrivateKey = "mocked_private_key";
18
+
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ vi.mocked(createClient).mockReturnValue(mockClient as any);
22
+ vi.mocked(createAccount).mockReturnValue({privateKey: mockPrivateKey} as any);
23
+ callActions = new CallAction();
24
+ vi.spyOn(callActions as any, "getAccount").mockResolvedValue({privateKey: mockPrivateKey});
25
+
26
+ vi.spyOn(callActions as any, "startSpinner").mockImplementation(() => {});
27
+ vi.spyOn(callActions as any, "succeedSpinner").mockImplementation(() => {});
28
+ vi.spyOn(callActions as any, "failSpinner").mockImplementation(() => {});
29
+ vi.spyOn(callActions as any, "log").mockImplementation(() => {});
30
+ });
31
+
32
+ afterEach(() => {
33
+ vi.restoreAllMocks();
34
+ });
35
+
36
+ test("calls readContract successfully", async () => {
37
+ const options = {args: [1, 2, "Hello"]};
38
+ const mockResult = "mocked_result";
39
+
40
+ vi.mocked(mockClient.readContract).mockResolvedValue(mockResult);
41
+
42
+ await callActions.call({
43
+ contractAddress: "0xMockedContract",
44
+ method: "getData",
45
+ ...options,
46
+ });
47
+
48
+ expect(mockClient.readContract).toHaveBeenCalledWith({
49
+ address: "0xMockedContract",
50
+ functionName: "getData",
51
+ args: [1, 2, "Hello"],
52
+ });
53
+ expect(callActions["succeedSpinner"]).toHaveBeenCalledWith(
54
+ "Read operation successfully executed",
55
+ "mocked_result",
56
+ );
57
+ });
58
+
59
+ test("handles readContract errors", async () => {
60
+ vi.mocked(mockClient.readContract).mockRejectedValue(new Error("Mocked read error"));
61
+
62
+ await callActions.call({contractAddress: "0xMockedContract", method: "getData", args: [1]});
63
+
64
+ expect(callActions["failSpinner"]).toHaveBeenCalledWith("Error during read operation", expect.any(Error));
65
+ });
66
+
67
+ test("uses custom RPC URL when provided", async () => {
68
+ const options = {args: [1, 2, "Hello"], rpc: "https://custom-rpc-url.com"};
69
+ const mockResult = "mocked_result";
70
+
71
+ vi.mocked(mockClient.readContract).mockResolvedValue(mockResult);
72
+
73
+ await callActions.call({
74
+ contractAddress: "0xMockedContract",
75
+ method: "getData",
76
+ ...options,
77
+ });
78
+
79
+ expect(createClient).toHaveBeenCalledWith(
80
+ expect.objectContaining({
81
+ endpoint: "https://custom-rpc-url.com",
82
+ }),
83
+ );
84
+ expect(mockClient.readContract).toHaveBeenCalledWith({
85
+ address: "0xMockedContract",
86
+ functionName: "getData",
87
+ args: [1, 2, "Hello"],
88
+ });
89
+ expect(callActions["succeedSpinner"]).toHaveBeenCalledWith(
90
+ "Read operation successfully executed",
91
+ "mocked_result",
92
+ );
93
+ });
94
+ });
@@ -0,0 +1,87 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import {createClient, createAccount} from "genlayer-js";
3
+ import {CodeAction} from "../../src/commands/contracts/code";
4
+
5
+ vi.mock("genlayer-js");
6
+
7
+ describe("CodeAction", () => {
8
+ let codeAction: CodeAction;
9
+ const mockClient = {
10
+ getContractCode: 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
+ codeAction = new CodeAction();
21
+ vi.spyOn(codeAction as any, "getAccount").mockResolvedValue({privateKey: mockPrivateKey});
22
+
23
+ vi.spyOn(codeAction as any, "startSpinner").mockImplementation(() => {});
24
+ vi.spyOn(codeAction as any, "succeedSpinner").mockImplementation(() => {});
25
+ vi.spyOn(codeAction as any, "failSpinner").mockImplementation(() => {});
26
+ vi.spyOn(codeAction as any, "log").mockImplementation(() => {});
27
+ });
28
+
29
+ afterEach(() => {
30
+ vi.restoreAllMocks();
31
+ });
32
+
33
+ test("gets contract code successfully", async () => {
34
+ const mockResult = "0x600160...";
35
+
36
+ vi.mocked(mockClient.getContractCode).mockResolvedValue(mockResult as any);
37
+
38
+ await codeAction.code({
39
+ contractAddress: "0xMockedContract",
40
+ });
41
+
42
+ expect(mockClient.getContractCode).toHaveBeenCalledWith("0xMockedContract");
43
+ expect(codeAction["succeedSpinner"]).toHaveBeenCalledWith(
44
+ "Contract code retrieved successfully",
45
+ mockResult,
46
+ );
47
+ });
48
+
49
+ test("handles getContractCode errors", async () => {
50
+ vi.mocked(mockClient.getContractCode).mockRejectedValue(new Error("Mocked code error"));
51
+
52
+ await codeAction.code({contractAddress: "0xMockedContract"});
53
+
54
+ expect(codeAction["failSpinner"]).toHaveBeenCalledWith("Error retrieving contract code", expect.any(Error));
55
+ });
56
+
57
+ test("uses custom RPC URL when provided", async () => {
58
+ const mockResult = "0x600160...";
59
+ vi.mocked(mockClient.getContractCode).mockResolvedValue(mockResult as any);
60
+
61
+ await codeAction.code({
62
+ contractAddress: "0xMockedContract",
63
+ rpc: "https://custom-rpc-url.com",
64
+ });
65
+
66
+ expect(createClient).toHaveBeenCalledWith(
67
+ expect.objectContaining({
68
+ endpoint: "https://custom-rpc-url.com",
69
+ }),
70
+ );
71
+ expect(mockClient.getContractCode).toHaveBeenCalledWith("0xMockedContract");
72
+ expect(codeAction["succeedSpinner"]).toHaveBeenCalledWith(
73
+ "Contract code retrieved successfully",
74
+ mockResult,
75
+ );
76
+ });
77
+
78
+ test("initializes consensus smart contract", async () => {
79
+ vi.mocked(mockClient.getContractCode).mockResolvedValue("0x" as any);
80
+
81
+ await codeAction.code({contractAddress: "0xMockedContract"});
82
+
83
+ expect(mockClient.initializeConsensusSmartContract).toHaveBeenCalled();
84
+ });
85
+ });
86
+
87
+
@@ -0,0 +1,65 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import {CreateAccountAction} from "../../src/commands/account/create";
3
+ import {readFileSync, existsSync} from "fs";
4
+ import os from "os";
5
+
6
+ vi.mock("fs");
7
+ vi.mock("os");
8
+
9
+ describe("CreateAccountAction", () => {
10
+ let createAction: CreateAccountAction;
11
+ const mockKeystorePath = "/mocked/home/.genlayer/keystores/main.json";
12
+
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ // Setup mocks before creating the action (needed for constructor)
16
+ vi.mocked(os.homedir).mockReturnValue("/mocked/home");
17
+ vi.mocked(existsSync).mockReturnValue(true);
18
+ vi.mocked(readFileSync).mockReturnValue(JSON.stringify({activeAccount: "default"}));
19
+
20
+ createAction = new CreateAccountAction();
21
+
22
+ // Mock the BaseAction methods
23
+ vi.spyOn(createAction as any, "startSpinner").mockImplementation(() => {});
24
+ vi.spyOn(createAction as any, "succeedSpinner").mockImplementation(() => {});
25
+ vi.spyOn(createAction as any, "failSpinner").mockImplementation(() => {});
26
+ vi.spyOn(createAction as any, "createKeypairByName").mockResolvedValue("0x1234567890abcdef");
27
+ vi.spyOn(createAction as any, "setActiveAccount").mockImplementation(() => {});
28
+ vi.spyOn(createAction as any, "getKeystorePath").mockReturnValue(mockKeystorePath);
29
+ });
30
+
31
+ afterEach(() => {
32
+ vi.restoreAllMocks();
33
+ });
34
+
35
+ test("successfully creates and saves an encrypted keystore", async () => {
36
+ const options = {name: "main", overwrite: false, setActive: true};
37
+
38
+ await createAction.execute(options);
39
+
40
+ expect(createAction["startSpinner"]).toHaveBeenCalledWith("Creating account 'main'...");
41
+ expect(createAction["createKeypairByName"]).toHaveBeenCalledWith("main", false, undefined);
42
+ expect(createAction["setActiveAccount"]).toHaveBeenCalledWith("main");
43
+ expect(createAction["succeedSpinner"]).toHaveBeenCalledWith(
44
+ `Account 'main' created at: ${mockKeystorePath}`,
45
+ );
46
+ });
47
+
48
+ test("handles errors during keystore creation", async () => {
49
+ const mockError = new Error("Mocked creation error");
50
+ vi.spyOn(createAction as any, "createKeypairByName").mockRejectedValue(mockError);
51
+
52
+ await createAction.execute({name: "main", overwrite: true});
53
+
54
+ expect(createAction["failSpinner"]).toHaveBeenCalledWith("Failed to create account", mockError);
55
+ });
56
+
57
+ test("skips setting active account when setActive is false", async () => {
58
+ const options = {name: "validator", overwrite: false, setActive: false};
59
+
60
+ await createAction.execute(options);
61
+
62
+ expect(createAction["setActiveAccount"]).not.toHaveBeenCalled();
63
+ expect(createAction["succeedSpinner"]).toHaveBeenCalled();
64
+ });
65
+ });
@@ -0,0 +1,420 @@
1
+ import {describe, test, vi, beforeEach, afterEach, expect} from "vitest";
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import {createClient, createAccount} from "genlayer-js";
5
+ import {DeployAction, DeployOptions} from "../../src/commands/contracts/deploy";
6
+ import {buildSync} from "esbuild";
7
+ import {pathToFileURL} from "url";
8
+
9
+ vi.mock("fs");
10
+ vi.mock("os");
11
+ vi.mock("genlayer-js");
12
+ vi.mock("esbuild", () => ({
13
+ buildSync: vi.fn(),
14
+ }));
15
+
16
+ describe("DeployAction", () => {
17
+ let deployer: DeployAction;
18
+ const mockClient = {
19
+ deployContract: vi.fn(),
20
+ waitForTransactionReceipt: vi.fn(),
21
+ initializeConsensusSmartContract: vi.fn(),
22
+ };
23
+
24
+ const mockPrivateKey = "mocked_private_key";
25
+
26
+ beforeEach(() => {
27
+ vi.clearAllMocks();
28
+ // Setup mocks before creating the action (needed for constructor)
29
+ vi.mocked(os.homedir).mockReturnValue("/mocked/home");
30
+ vi.mocked(fs.existsSync).mockReturnValue(true);
31
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({activeAccount: "default"}));
32
+
33
+ vi.mocked(createClient).mockReturnValue(mockClient as any);
34
+ vi.mocked(createAccount).mockReturnValue({privateKey: mockPrivateKey} as any);
35
+ deployer = new DeployAction();
36
+ vi.spyOn(deployer as any, "getAccount").mockResolvedValue({privateKey: mockPrivateKey});
37
+ vi.spyOn(deployer as any, "getConfig").mockReturnValue({});
38
+
39
+ vi.spyOn(deployer as any, "startSpinner").mockImplementation(() => {});
40
+ vi.spyOn(deployer as any, "succeedSpinner").mockImplementation(() => {});
41
+ vi.spyOn(deployer as any, "failSpinner").mockImplementation(() => {});
42
+ vi.spyOn(deployer as any, "setSpinnerText").mockImplementation(() => {});
43
+ vi.spyOn(deployer as any, "log").mockImplementation(() => {});
44
+ });
45
+
46
+ afterEach(() => {
47
+ vi.restoreAllMocks();
48
+ });
49
+
50
+ test("reads contract code successfully", () => {
51
+ const contractPath = "/mocked/contract/path";
52
+ const contractContent = "contract code";
53
+ vi.mocked(fs.existsSync).mockReturnValue(true);
54
+ vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
55
+
56
+ const result = deployer["readContractCode"](contractPath);
57
+
58
+ expect(fs.existsSync).toHaveBeenCalledWith(contractPath);
59
+ expect(fs.readFileSync).toHaveBeenCalledWith(contractPath, "utf-8");
60
+ expect(result).toBe(contractContent);
61
+ });
62
+
63
+ test("throws error if contract file is missing", () => {
64
+ const contractPath = "/mocked/contract/path";
65
+ vi.mocked(fs.existsSync).mockReturnValue(false);
66
+
67
+ expect(() => deployer["readContractCode"](contractPath)).toThrowError(
68
+ `Contract file not found: ${contractPath}`,
69
+ );
70
+ expect(fs.existsSync).toHaveBeenCalledWith(contractPath);
71
+ });
72
+
73
+ test("deploys contract with args", async () => {
74
+ const options: DeployOptions = {
75
+ contract: "/mocked/contract/path",
76
+ args: [1, 2, 3],
77
+ };
78
+ const contractContent = "contract code";
79
+
80
+ vi.mocked(fs.existsSync).mockReturnValue(true);
81
+ vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
82
+ vi.mocked(mockClient.deployContract).mockResolvedValue("mocked_tx_hash");
83
+ vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue({
84
+ data: {contract_address: "0xdasdsadasdasdada"},
85
+ });
86
+
87
+ await deployer.deploy(options);
88
+
89
+ expect(fs.readFileSync).toHaveBeenCalledWith(options.contract, "utf-8");
90
+ expect(mockClient.deployContract).toHaveBeenCalledWith({
91
+ code: contractContent,
92
+ args: [1, 2, 3],
93
+ leaderOnly: false,
94
+ });
95
+ expect(mockClient.deployContract).toHaveReturnedWith(Promise.resolve("mocked_tx_hash"));
96
+ });
97
+
98
+ test("throws error for missing contract", async () => {
99
+ const options: DeployOptions = {};
100
+
101
+ await deployer.deploy(options);
102
+
103
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("No contract specified for deployment.");
104
+ expect(mockClient.deployContract).not.toHaveBeenCalled();
105
+ });
106
+
107
+ test("handles deployment errors", async () => {
108
+ const options: DeployOptions = {
109
+ contract: "/mocked/contract/path",
110
+ args: [1, 2, 3],
111
+ };
112
+ const contractContent = "contract code";
113
+
114
+ vi.mocked(fs.existsSync).mockReturnValue(true);
115
+ vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
116
+ vi.mocked(mockClient.deployContract).mockRejectedValue(new Error("Mocked deployment error"));
117
+
118
+ await deployer.deploy(options);
119
+
120
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("Error deploying contract", expect.any(Error));
121
+ expect(mockClient.deployContract).toHaveBeenCalled();
122
+ });
123
+
124
+ test("handles empty contract code", async () => {
125
+ const options: DeployOptions = {
126
+ contract: "/mocked/contract/path",
127
+ };
128
+
129
+ vi.mocked(fs.existsSync).mockReturnValue(true);
130
+ vi.mocked(fs.readFileSync).mockReturnValue("");
131
+
132
+ await deployer.deploy(options);
133
+
134
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("Contract code is empty.");
135
+ expect(mockClient.deployContract).not.toHaveBeenCalled();
136
+ });
137
+
138
+ test("deployScripts executes scripts in order", async () => {
139
+ vi.mocked(fs.existsSync).mockReturnValue(true);
140
+ vi.mocked(fs.readdirSync).mockReturnValue(["1_first.ts", "2_second.js", "10_last.ts"] as any);
141
+
142
+ vi.spyOn(deployer as any, "executeTsScript").mockResolvedValue(undefined);
143
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
144
+
145
+ await deployer.deployScripts();
146
+
147
+ expect(deployer["setSpinnerText"]).toHaveBeenCalledWith("Found 3 deploy scripts. Executing...");
148
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(expect.stringMatching(/1_first.ts/), undefined);
149
+ expect(deployer["executeJsScript"]).toHaveBeenCalledWith(
150
+ expect.stringMatching(/2_second.js/),
151
+ undefined,
152
+ undefined,
153
+ );
154
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(expect.stringMatching(/10_last.ts/), undefined);
155
+ });
156
+
157
+ test("executeTsScript transpiles and executes TypeScript", async () => {
158
+ const filePath = "/mocked/script.ts";
159
+ const outFile = "/mocked/script.compiled.js";
160
+
161
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
162
+ vi.mocked(buildSync).mockImplementation((() => {}) as any);
163
+
164
+ await deployer["executeTsScript"](filePath);
165
+
166
+ expect(deployer["startSpinner"]).toHaveBeenCalledWith(`Transpiling TypeScript file: ${filePath}`);
167
+ expect(buildSync).toHaveBeenCalledWith({
168
+ entryPoints: [filePath],
169
+ outfile: outFile,
170
+ bundle: false,
171
+ platform: "node",
172
+ format: "esm",
173
+ target: "es2020",
174
+ sourcemap: false,
175
+ });
176
+
177
+ expect(deployer["executeJsScript"]).toHaveBeenCalledWith(filePath, outFile, undefined);
178
+ expect(fs.unlinkSync).toHaveBeenCalledWith(outFile);
179
+ });
180
+
181
+ test("deployScripts fails when deploy folder is missing", async () => {
182
+ vi.mocked(fs.existsSync).mockReturnValue(false);
183
+
184
+ await deployer.deployScripts();
185
+
186
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("No deploy folder found.");
187
+ });
188
+
189
+ test("deployScripts sorts and executes scripts correctly", async () => {
190
+ vi.mocked(fs.existsSync).mockReturnValue(true);
191
+ vi.mocked(fs.readdirSync).mockReturnValue(["10_last.ts", "2_second.js", "1_first.ts"] as any);
192
+
193
+ vi.spyOn(deployer as any, "executeTsScript").mockResolvedValue(undefined);
194
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
195
+
196
+ await deployer.deployScripts();
197
+
198
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
199
+ expect.stringContaining("1_first.ts"),
200
+ undefined,
201
+ );
202
+ expect(deployer["executeJsScript"]).toHaveBeenCalledWith(
203
+ expect.stringContaining("2_second.js"),
204
+ undefined,
205
+ undefined,
206
+ );
207
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
208
+ expect.stringContaining("10_last.ts"),
209
+ undefined,
210
+ );
211
+ });
212
+
213
+ test("deployScripts fails when no scripts are found", async () => {
214
+ vi.mocked(fs.existsSync).mockReturnValue(true);
215
+ vi.mocked(fs.readdirSync).mockReturnValue([]);
216
+
217
+ await deployer.deployScripts();
218
+
219
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("No deploy scripts found.");
220
+ });
221
+
222
+ test("deployScripts handles script execution errors", async () => {
223
+ vi.mocked(fs.existsSync).mockReturnValue(true);
224
+ vi.mocked(fs.readdirSync).mockReturnValue(["1_failing.ts"] as any);
225
+ vi.spyOn(deployer as any, "executeTsScript").mockRejectedValue(new Error("Script error"));
226
+
227
+ await deployer.deployScripts();
228
+
229
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith(
230
+ expect.stringContaining("Error executing script:"),
231
+ expect.any(Error),
232
+ );
233
+ });
234
+
235
+ test("executeJsScript fails gracefully", async () => {
236
+ const filePath = "/mocked/script.js";
237
+
238
+ await deployer["executeJsScript"](filePath);
239
+
240
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith(
241
+ expect.stringContaining("Error executing:"),
242
+ expect.any(Error),
243
+ );
244
+ });
245
+
246
+ test("deploy fails when contract code is empty", async () => {
247
+ const options: DeployOptions = {contract: "/mocked/contract/path"};
248
+
249
+ vi.mocked(fs.existsSync).mockReturnValue(true);
250
+ vi.mocked(fs.readFileSync).mockReturnValue("");
251
+
252
+ await deployer.deploy(options);
253
+
254
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith("Contract code is empty.");
255
+ });
256
+
257
+ test("deployScripts correctly sorts mixed numbered and non-numbered scripts", async () => {
258
+ vi.mocked(fs.existsSync).mockReturnValue(true);
259
+ vi.mocked(fs.readdirSync).mockReturnValue([
260
+ "script.ts",
261
+ "2alpha_script.ts",
262
+ "3alpha_script.ts",
263
+ "blpha_script.ts",
264
+ "clpha_script.ts",
265
+ ] as any);
266
+
267
+ vi.spyOn(deployer as any, "executeTsScript").mockResolvedValue(undefined);
268
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
269
+
270
+ await deployer.deployScripts();
271
+
272
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(expect.stringContaining("script.ts"), undefined);
273
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
274
+ expect.stringContaining("2alpha_script.ts"),
275
+ undefined,
276
+ );
277
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
278
+ expect.stringContaining("3alpha_script.ts"),
279
+ undefined,
280
+ );
281
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
282
+ expect.stringContaining("blpha_script.ts"),
283
+ undefined,
284
+ );
285
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(
286
+ expect.stringContaining("clpha_script.ts"),
287
+ undefined,
288
+ );
289
+ });
290
+
291
+ test("executeJsScript fails if module has no default export", async () => {
292
+ const filePath = "/mocked/script.js";
293
+
294
+ vi.doMock(pathToFileURL(filePath).href, () => ({default: "Not a function"}));
295
+
296
+ await deployer["executeJsScript"](filePath);
297
+
298
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith(
299
+ expect.stringContaining('No "default" function found in:'),
300
+ );
301
+ });
302
+
303
+ test("executeJsScript successfully executes a script", async () => {
304
+ const filePath = "/mocked/script.js";
305
+ const mockFn = vi.fn(); // This mock function simulates the script execution
306
+
307
+ vi.doMock(pathToFileURL(filePath).href, () => ({default: mockFn}));
308
+
309
+ await deployer["executeJsScript"](filePath);
310
+
311
+ expect(mockFn).toHaveBeenCalledWith(mockClient);
312
+
313
+ expect(deployer["succeedSpinner"]).toHaveBeenCalledWith(`Successfully executed: ${filePath}`);
314
+ });
315
+
316
+ test("executeTsScript fails when buildSync throws an error", async () => {
317
+ const filePath = "/mocked/script.ts";
318
+ const error = new Error("Build failed");
319
+
320
+ vi.mocked(buildSync).mockImplementation(() => {
321
+ throw error; // Simulate an error during transpilation
322
+ });
323
+
324
+ await deployer["executeTsScript"](filePath);
325
+
326
+ expect(deployer["failSpinner"]).toHaveBeenCalledWith(`Error executing: ${filePath}`, error);
327
+ });
328
+
329
+ test("deploys contract with rpc option", async () => {
330
+ const options: DeployOptions = {
331
+ contract: "/mocked/contract/path",
332
+ args: [1, 2, 3],
333
+ rpc: "https://custom-rpc-url.com",
334
+ };
335
+ const contractContent = "contract code";
336
+
337
+ vi.mocked(fs.existsSync).mockReturnValue(true);
338
+ vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
339
+ vi.mocked(mockClient.deployContract).mockResolvedValue("mocked_tx_hash");
340
+ vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue({
341
+ data: {contract_address: "0xdasdsadasdasdada"},
342
+ });
343
+
344
+ await deployer.deploy(options);
345
+
346
+ expect(createClient).toHaveBeenCalledWith(
347
+ expect.objectContaining({
348
+ endpoint: "https://custom-rpc-url.com",
349
+ }),
350
+ );
351
+ expect(fs.readFileSync).toHaveBeenCalledWith(options.contract, "utf-8");
352
+ expect(mockClient.deployContract).toHaveBeenCalledWith({
353
+ code: contractContent,
354
+ args: [1, 2, 3],
355
+ leaderOnly: false,
356
+ });
357
+ });
358
+
359
+ test("executeJsScript uses rpc url when provided", async () => {
360
+ const filePath = "/mocked/script.js";
361
+ const rpcUrl = "https://custom-rpc-url.com";
362
+ const mockFn = vi.fn();
363
+
364
+ vi.doMock(pathToFileURL(filePath).href, () => ({default: mockFn}));
365
+
366
+ await deployer["executeJsScript"](filePath, undefined, rpcUrl);
367
+
368
+ expect(createClient).toHaveBeenCalledWith(
369
+ expect.objectContaining({
370
+ endpoint: rpcUrl,
371
+ }),
372
+ );
373
+ expect(mockFn).toHaveBeenCalledWith(mockClient);
374
+ expect(deployer["succeedSpinner"]).toHaveBeenCalledWith(`Successfully executed: ${filePath}`);
375
+ });
376
+
377
+ test("executeTsScript passes rpc url to executeJsScript", async () => {
378
+ const filePath = "/mocked/script.ts";
379
+ const outFile = "/mocked/script.compiled.js";
380
+ const rpcUrl = "https://custom-rpc-url.com";
381
+
382
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
383
+ vi.mocked(buildSync).mockImplementation((() => {}) as any);
384
+
385
+ await deployer["executeTsScript"](filePath, rpcUrl);
386
+
387
+ expect(deployer["startSpinner"]).toHaveBeenCalledWith(`Transpiling TypeScript file: ${filePath}`);
388
+ expect(buildSync).toHaveBeenCalledWith({
389
+ entryPoints: [filePath],
390
+ outfile: outFile,
391
+ bundle: false,
392
+ platform: "node",
393
+ format: "esm",
394
+ target: "es2020",
395
+ sourcemap: false,
396
+ });
397
+
398
+ expect(deployer["executeJsScript"]).toHaveBeenCalledWith(filePath, outFile, rpcUrl);
399
+ expect(fs.unlinkSync).toHaveBeenCalledWith(outFile);
400
+ });
401
+
402
+ test("deployScripts passes rpc url to script execution methods", async () => {
403
+ const rpcUrl = "https://custom-rpc-url.com";
404
+
405
+ vi.mocked(fs.existsSync).mockReturnValue(true);
406
+ vi.mocked(fs.readdirSync).mockReturnValue(["1_first.ts", "2_second.js"] as any);
407
+
408
+ vi.spyOn(deployer as any, "executeTsScript").mockResolvedValue(undefined);
409
+ vi.spyOn(deployer as any, "executeJsScript").mockResolvedValue(undefined);
410
+
411
+ await deployer.deployScripts({rpc: rpcUrl});
412
+
413
+ expect(deployer["executeTsScript"]).toHaveBeenCalledWith(expect.stringMatching(/1_first.ts/), rpcUrl);
414
+ expect(deployer["executeJsScript"]).toHaveBeenCalledWith(
415
+ expect.stringMatching(/2_second.js/),
416
+ undefined,
417
+ rpcUrl,
418
+ );
419
+ });
420
+ });