genlayer 0.7.0 → 0.8.1-beta.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/.env.example +10 -0
- package/CHANGELOG.md +14 -0
- package/dist/index.js +31012 -17765
- package/docker-compose.yml +13 -6
- package/esbuild.config.dev +1 -1
- package/esbuild.config.prod +1 -1
- package/package.json +3 -1
- package/src/commands/config/getSetReset.ts +44 -0
- package/src/commands/config/index.ts +30 -0
- package/src/commands/contracts/call.ts +83 -0
- package/src/commands/contracts/deploy.ts +72 -0
- package/src/commands/contracts/index.ts +27 -0
- package/src/commands/general/index.ts +1 -2
- package/src/index.ts +4 -0
- package/src/lib/accounts/getPrivateKey.ts +21 -0
- package/tests/actions/call.test.ts +144 -0
- package/tests/actions/create.test.ts +1 -1
- package/tests/actions/deploy.test.ts +139 -0
- package/tests/actions/getSetReset.test.ts +101 -0
- package/tests/commands/call.test.ts +91 -0
- package/tests/commands/config.test.ts +54 -0
- package/tests/commands/deploy.test.ts +69 -0
- package/tests/index.test.ts +8 -0
- package/tests/libs/getPrivateKey.test.ts +96 -0
- package/tsconfig.json +1 -1
package/docker-compose.yml
CHANGED
|
@@ -7,8 +7,8 @@ services:
|
|
|
7
7
|
- "${FRONTEND_PORT:-8080}:8080"
|
|
8
8
|
environment:
|
|
9
9
|
- VITE_*
|
|
10
|
-
|
|
11
|
-
- ./.env
|
|
10
|
+
env_file:
|
|
11
|
+
- ./.env
|
|
12
12
|
depends_on:
|
|
13
13
|
jsonrpc:
|
|
14
14
|
condition: service_healthy
|
|
@@ -36,8 +36,8 @@ services:
|
|
|
36
36
|
ports:
|
|
37
37
|
- "${RPCPORT:-5000}:${RPCPORT:-5000}"
|
|
38
38
|
- "${RPCDEBUGPORT:-5001}:${RPCDEBUGPORT:-5001}"
|
|
39
|
-
|
|
40
|
-
- ./.env
|
|
39
|
+
env_file:
|
|
40
|
+
- ./.env
|
|
41
41
|
healthcheck:
|
|
42
42
|
test: [ "CMD", "python", "backend/healthcheck.py", "--port", "${RPCPORT}" ]
|
|
43
43
|
interval: 30s
|
|
@@ -75,8 +75,8 @@ services:
|
|
|
75
75
|
expose:
|
|
76
76
|
- "${WEBREQUESTPORT:-5002}:${WEBREQUESTPORT:-5002}"
|
|
77
77
|
- "${WEBREQUESTSELENIUMPORT:-4444}:${WEBREQUESTSELENIUMPORT:-4444}"
|
|
78
|
-
|
|
79
|
-
- ./.env
|
|
78
|
+
env_file:
|
|
79
|
+
- ./.env
|
|
80
80
|
depends_on:
|
|
81
81
|
ollama:
|
|
82
82
|
condition: service_started
|
|
@@ -142,3 +142,10 @@ services:
|
|
|
142
142
|
condition: service_healthy
|
|
143
143
|
webrequest:
|
|
144
144
|
condition: service_healthy
|
|
145
|
+
|
|
146
|
+
hardhat:
|
|
147
|
+
image: yeagerai/simulator-hardhat
|
|
148
|
+
ports:
|
|
149
|
+
- "${HARDHAT_PORT:-8545}:8545"
|
|
150
|
+
environment:
|
|
151
|
+
- HARDHAT_NETWORK=hardhat
|
package/esbuild.config.dev
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
bundle: true, // Bundle all dependencies
|
|
6
6
|
outfile: "dist/index.js", // Output file
|
|
7
7
|
platform: "node",
|
|
8
|
-
target: "
|
|
8
|
+
target: "es2020",
|
|
9
9
|
define: { 'import.meta.url': '_importMetaUrl' },
|
|
10
10
|
banner: {
|
|
11
11
|
js: "const _importMetaUrl=require('url').pathToFileURL(__filename)",
|
package/esbuild.config.prod
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
bundle: true, // Bundle all dependencies
|
|
6
6
|
outfile: "dist/index.js", // Output file
|
|
7
7
|
platform: "node",
|
|
8
|
-
target: "
|
|
8
|
+
target: "es2020",
|
|
9
9
|
define: { 'import.meta.url': '_importMetaUrl' },
|
|
10
10
|
banner: {
|
|
11
11
|
js: "const _importMetaUrl=require('url').pathToFileURL(__filename)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genlayer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1-beta.0",
|
|
4
4
|
"description": "GenLayer Command Line Tool",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -60,11 +60,13 @@
|
|
|
60
60
|
"dockerode": "^4.0.2",
|
|
61
61
|
"dotenv": "^16.4.5",
|
|
62
62
|
"ethers": "^6.13.4",
|
|
63
|
+
"genlayer-js": "^0.4.7",
|
|
63
64
|
"inquirer": "^9.2.19",
|
|
64
65
|
"node-fetch": "^2.7.0",
|
|
65
66
|
"open": "^10.1.0",
|
|
66
67
|
"update-check": "^1.5.4",
|
|
67
68
|
"uuid": "^9.0.1",
|
|
69
|
+
"viem": "^2.21.54",
|
|
68
70
|
"vitest": "^2.1.4"
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ConfigFileManager } from "../../lib/config/ConfigFileManager";
|
|
2
|
+
|
|
3
|
+
export class ConfigActions {
|
|
4
|
+
private configManager: ConfigFileManager;
|
|
5
|
+
|
|
6
|
+
constructor() {
|
|
7
|
+
this.configManager = new ConfigFileManager();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
set(keyValue: string): void {
|
|
11
|
+
const [key, value] = keyValue.split("=");
|
|
12
|
+
if (!key || value === undefined) {
|
|
13
|
+
console.error("Invalid format. Use key=value.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
this.configManager.writeConfig(key, value);
|
|
17
|
+
console.log(`Configuration updated: ${key}=${value}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get(key?: string): void {
|
|
21
|
+
if (key) {
|
|
22
|
+
const value = this.configManager.getConfigByKey(key);
|
|
23
|
+
if (value === null) {
|
|
24
|
+
console.log(`No value set for key: ${key}`);
|
|
25
|
+
} else {
|
|
26
|
+
console.log(`${key}=${value}`);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
const config = this.configManager.getConfig();
|
|
30
|
+
console.log("Current configuration:", JSON.stringify(config, null, 2));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
reset(key: string): void {
|
|
35
|
+
const config = this.configManager.getConfig();
|
|
36
|
+
if (config[key] === undefined) {
|
|
37
|
+
console.log(`Key does not exist in the configuration: ${key}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
delete config[key];
|
|
41
|
+
this.configManager.writeConfig(key, undefined);
|
|
42
|
+
console.log(`Configuration key reset: ${key}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { ConfigActions } from "./getSetReset";
|
|
3
|
+
|
|
4
|
+
export function initializeConfigCommands(program: Command) {
|
|
5
|
+
const configActions = new ConfigActions();
|
|
6
|
+
|
|
7
|
+
const configCommand = program
|
|
8
|
+
.command("config")
|
|
9
|
+
.description("Manage CLI configuration, including the default network");
|
|
10
|
+
|
|
11
|
+
configCommand
|
|
12
|
+
.command("set")
|
|
13
|
+
.description("Set a configuration value")
|
|
14
|
+
.argument("<key=value>", "Configuration key-value pair to set")
|
|
15
|
+
.action((keyValue: string) => configActions.set(keyValue));
|
|
16
|
+
|
|
17
|
+
configCommand
|
|
18
|
+
.command("get")
|
|
19
|
+
.description("Get the current configuration")
|
|
20
|
+
.argument("[key]", "Configuration key to retrieve")
|
|
21
|
+
.action((key?: string) => configActions.get(key));
|
|
22
|
+
|
|
23
|
+
configCommand
|
|
24
|
+
.command("reset")
|
|
25
|
+
.description("Reset a configuration value to its default")
|
|
26
|
+
.argument("<key>", "Configuration key to reset")
|
|
27
|
+
.action((key: string) => configActions.reset(key));
|
|
28
|
+
|
|
29
|
+
return program;
|
|
30
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createClient, createAccount } from "genlayer-js";
|
|
2
|
+
import { simulator } from "genlayer-js/chains";
|
|
3
|
+
import type { GenLayerClient } from "genlayer-js/types";
|
|
4
|
+
import { getPrivateKey } from "../../lib/accounts/getPrivateKey";
|
|
5
|
+
|
|
6
|
+
export interface CallOptions {
|
|
7
|
+
args: any[];
|
|
8
|
+
type: "read" | "write";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class CallAction {
|
|
12
|
+
private genlayerClient: GenLayerClient<typeof simulator>;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.genlayerClient = createClient({
|
|
16
|
+
chain: simulator,
|
|
17
|
+
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
|
|
18
|
+
account: createAccount(getPrivateKey() as any),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async call({
|
|
23
|
+
contractAddress,
|
|
24
|
+
method,
|
|
25
|
+
args,
|
|
26
|
+
type,
|
|
27
|
+
}: {
|
|
28
|
+
contractAddress: string;
|
|
29
|
+
method: string;
|
|
30
|
+
args: any[];
|
|
31
|
+
type: "read" | "write";
|
|
32
|
+
}): Promise<void> {
|
|
33
|
+
console.log(`Calling ${type} method ${method} on contract at ${contractAddress}...`);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
if (type === "read") {
|
|
37
|
+
await this.executeRead(contractAddress, method, args);
|
|
38
|
+
} else if (type === "write") {
|
|
39
|
+
await this.executeWrite(contractAddress, method, args);
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error(`Invalid call type: ${type}. Use "read" or "write".`);
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("Error calling contract method:", error);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private async executeRead(contractAddress: string, method: string, args: any[]): Promise<void> {
|
|
50
|
+
try {
|
|
51
|
+
const result = await this.genlayerClient.readContract({
|
|
52
|
+
address: contractAddress as any,
|
|
53
|
+
functionName: method,
|
|
54
|
+
args,
|
|
55
|
+
});
|
|
56
|
+
console.log("Read result:", result);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error("Error during read operation:", error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private async executeWrite(contractAddress: string, method: string, args: any[]): Promise<void> {
|
|
64
|
+
try {
|
|
65
|
+
const hash = await this.genlayerClient.writeContract({
|
|
66
|
+
address: contractAddress as any,
|
|
67
|
+
functionName: method,
|
|
68
|
+
args,
|
|
69
|
+
value: 0n,
|
|
70
|
+
});
|
|
71
|
+
const result = await this.genlayerClient.waitForTransactionReceipt({
|
|
72
|
+
hash,
|
|
73
|
+
retries: 15,
|
|
74
|
+
interval: 2000,
|
|
75
|
+
});
|
|
76
|
+
console.log("Write transaction hash:", hash);
|
|
77
|
+
console.log("Result:", result);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error("Error during write operation:", error);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { createClient, createAccount } from "genlayer-js";
|
|
3
|
+
import { simulator } from "genlayer-js/chains";
|
|
4
|
+
import type { GenLayerClient } from "genlayer-js/types";
|
|
5
|
+
import { getPrivateKey } from "../../lib/accounts/getPrivateKey";
|
|
6
|
+
|
|
7
|
+
export interface DeployOptions {
|
|
8
|
+
contract?: string;
|
|
9
|
+
// network: string;
|
|
10
|
+
args?: any[];
|
|
11
|
+
kwargs?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class DeployAction {
|
|
15
|
+
private genlayerClient: GenLayerClient<typeof simulator>;
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
this.genlayerClient = createClient({
|
|
19
|
+
chain: simulator,
|
|
20
|
+
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
|
|
21
|
+
account: createAccount(getPrivateKey() as any),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private readContractCode(contractPath: string): string {
|
|
26
|
+
if (!fs.existsSync(contractPath)) {
|
|
27
|
+
throw new Error(`Contract file not found: ${contractPath}`);
|
|
28
|
+
}
|
|
29
|
+
return fs.readFileSync(contractPath, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async deploy(options: DeployOptions): Promise<void> {
|
|
33
|
+
|
|
34
|
+
const argsUsed = options.args && options.args.length > 0;
|
|
35
|
+
const kwargsUsed = options.kwargs && options.kwargs.trim() !== "";
|
|
36
|
+
|
|
37
|
+
if (argsUsed && kwargsUsed) {
|
|
38
|
+
throw new Error("Invalid usage: Please specify either `args` or `kwargs`, but not both.");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!options.contract) {
|
|
42
|
+
console.error("No contract specified for deployment.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const contractCode = this.readContractCode(options.contract);
|
|
47
|
+
|
|
48
|
+
if (!contractCode) {
|
|
49
|
+
console.error("Contract code is empty.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const leaderOnly = false;
|
|
54
|
+
let deployParams: any = { code: contractCode, args: options.args, leaderOnly };
|
|
55
|
+
|
|
56
|
+
console.log("Starting contract deployment...");
|
|
57
|
+
console.log("Deployment Parameters:", deployParams);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const hash = await this.genlayerClient.deployContract(deployParams) as any;
|
|
61
|
+
|
|
62
|
+
const result = await this.genlayerClient.waitForTransactionReceipt({hash, retries: 15, interval: 2000})
|
|
63
|
+
|
|
64
|
+
console.log("Contract deployed successfully.");
|
|
65
|
+
console.log("Transaction Hash:", hash);
|
|
66
|
+
console.log("Contract Address:", result.data?.contract_address);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Error deploying contract:", error);
|
|
69
|
+
throw new Error("Contract deployment failed.");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { DeployAction, DeployOptions } from "./deploy";
|
|
3
|
+
import { CallAction, CallOptions } from "./call";
|
|
4
|
+
|
|
5
|
+
export function initializeContractsCommands(program: Command) {
|
|
6
|
+
program
|
|
7
|
+
.command("deploy")
|
|
8
|
+
.description("Deploy intelligent contracts")
|
|
9
|
+
.option("--contract <contractPath>", "Path to the smart contract to deploy")
|
|
10
|
+
.option("--args <args...>", "Positional arguments for the contract (space-separated, use quotes for multi-word arguments)", [])
|
|
11
|
+
.action(async (options: DeployOptions) => {
|
|
12
|
+
const deployer = new DeployAction();
|
|
13
|
+
await deployer.deploy(options);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command("call <contractAddress> <method>")
|
|
18
|
+
.description("Call a contract method")
|
|
19
|
+
.option("--args <args...>", "Positional arguments for the method (space-separated, use quotes for multi-word arguments)", [])
|
|
20
|
+
.option("--type <type>", "Type of call: read or write (default is read)", "read")
|
|
21
|
+
.action(async (contractAddress: string, method: string, options: CallOptions) => {
|
|
22
|
+
const caller = new CallAction();
|
|
23
|
+
await caller.call({ contractAddress, method, ...options });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return program;
|
|
27
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
|
|
3
2
|
import simulatorService from "../../lib/services/simulator";
|
|
4
3
|
import { initAction, InitActionOptions } from "./init";
|
|
5
4
|
import { startAction, StartActionOptions } from "./start";
|
|
@@ -11,7 +10,7 @@ export function initializeGeneralCommands(program: Command) {
|
|
|
11
10
|
.option("--numValidators <numValidators>", "Number of validators", "5")
|
|
12
11
|
.option("--headless", "Headless mode", false)
|
|
13
12
|
.option("--reset-db", "Reset Database", false)
|
|
14
|
-
.option("--localnet-version <localnetVersion>", "Select a specific localnet version",
|
|
13
|
+
.option("--localnet-version <localnetVersion>", "Select a specific localnet version", "latest")
|
|
15
14
|
.action((options: InitActionOptions) => initAction(options, simulatorService));
|
|
16
15
|
|
|
17
16
|
program
|
package/src/index.ts
CHANGED
|
@@ -4,11 +4,15 @@ import {version} from "../package.json";
|
|
|
4
4
|
import {CLI_DESCRIPTION} from "../src/lib/config/text";
|
|
5
5
|
import { initializeGeneralCommands } from "../src/commands/general";
|
|
6
6
|
import { initializeKeygenCommands } from "../src/commands/keygen";
|
|
7
|
+
import { initializeContractsCommands } from "../src/commands/contracts";
|
|
8
|
+
import { initializeConfigCommands } from "../src/commands/config";
|
|
7
9
|
|
|
8
10
|
export function initializeCLI() {
|
|
9
11
|
program.version(version).description(CLI_DESCRIPTION);
|
|
10
12
|
initializeGeneralCommands(program);
|
|
11
13
|
initializeKeygenCommands(program);
|
|
14
|
+
initializeContractsCommands(program);
|
|
15
|
+
initializeConfigCommands(program);
|
|
12
16
|
program.parse(process.argv);
|
|
13
17
|
}
|
|
14
18
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { ConfigFileManager } from "../config/ConfigFileManager";
|
|
3
|
+
|
|
4
|
+
export function getPrivateKey(): string {
|
|
5
|
+
const configFileManager: ConfigFileManager = new ConfigFileManager();
|
|
6
|
+
const keypairPath = configFileManager.getConfigByKey("keyPairPath");
|
|
7
|
+
|
|
8
|
+
if (!keypairPath || !fs.existsSync(keypairPath)) {
|
|
9
|
+
console.error("Keypair file not found. Please generate or specify a valid keypair path.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const keypairData = JSON.parse(fs.readFileSync(keypairPath, "utf-8"));
|
|
14
|
+
|
|
15
|
+
if (!keypairData.privateKey) {
|
|
16
|
+
console.error("Invalid keypair file. Private key is missing.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return keypairData.privateKey;
|
|
21
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
|
|
2
|
+
import { createClient, createAccount } from "genlayer-js";
|
|
3
|
+
import { CallAction, CallOptions } from "../../src/commands/contracts/call";
|
|
4
|
+
import { getPrivateKey } from "../../src/lib/accounts/getPrivateKey";
|
|
5
|
+
|
|
6
|
+
vi.mock("genlayer-js");
|
|
7
|
+
vi.mock("../../src/lib/accounts/getPrivateKey");
|
|
8
|
+
|
|
9
|
+
describe("Call Action", () => {
|
|
10
|
+
let caller: CallAction;
|
|
11
|
+
const mockClient = {
|
|
12
|
+
readContract: vi.fn(),
|
|
13
|
+
writeContract: vi.fn(),
|
|
14
|
+
waitForTransactionReceipt: 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
|
+
vi.mocked(getPrivateKey).mockReturnValue(mockPrivateKey);
|
|
24
|
+
caller = new CallAction();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("calls readContract successfully", async () => {
|
|
32
|
+
const options: CallOptions = {
|
|
33
|
+
args: [1, 2, "Hello"],
|
|
34
|
+
type: "read",
|
|
35
|
+
};
|
|
36
|
+
const mockResult = "mocked_result";
|
|
37
|
+
|
|
38
|
+
vi.mocked(mockClient.readContract).mockResolvedValue(mockResult);
|
|
39
|
+
|
|
40
|
+
await caller.call({
|
|
41
|
+
contractAddress: "0xMockedContract",
|
|
42
|
+
method: "getData",
|
|
43
|
+
...options,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(mockClient.readContract).toHaveBeenCalledWith({
|
|
47
|
+
address: "0xMockedContract",
|
|
48
|
+
functionName: "getData",
|
|
49
|
+
args: [1, 2, "Hello"],
|
|
50
|
+
});
|
|
51
|
+
expect(mockClient.readContract).toHaveResolvedWith(mockResult);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("calls writeContract successfully", async () => {
|
|
55
|
+
const options: CallOptions = {
|
|
56
|
+
args: [42, "Update"],
|
|
57
|
+
type: "write",
|
|
58
|
+
};
|
|
59
|
+
const mockHash = "0xMockedTransactionHash";
|
|
60
|
+
const mockReceipt = { status: "success" };
|
|
61
|
+
|
|
62
|
+
vi.mocked(mockClient.writeContract).mockResolvedValue(mockHash);
|
|
63
|
+
vi.mocked(mockClient.waitForTransactionReceipt).mockResolvedValue(mockReceipt);
|
|
64
|
+
|
|
65
|
+
await caller.call({
|
|
66
|
+
contractAddress: "0xMockedContract",
|
|
67
|
+
method: "updateData",
|
|
68
|
+
...options,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(mockClient.writeContract).toHaveBeenCalledWith({
|
|
72
|
+
address: "0xMockedContract",
|
|
73
|
+
functionName: "updateData",
|
|
74
|
+
args: [42, "Update"],
|
|
75
|
+
value: 0n,
|
|
76
|
+
});
|
|
77
|
+
expect(mockClient.waitForTransactionReceipt).toHaveBeenCalledWith({
|
|
78
|
+
hash: mockHash,
|
|
79
|
+
retries: 15,
|
|
80
|
+
interval: 2000,
|
|
81
|
+
});
|
|
82
|
+
expect(mockClient.writeContract).toHaveResolvedWith(mockHash);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("throws error for invalid call type", async () => {
|
|
86
|
+
const options: CallOptions = {
|
|
87
|
+
args: [],
|
|
88
|
+
type: "invalid" as any,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
await expect(
|
|
92
|
+
caller.call({
|
|
93
|
+
contractAddress: "0xMockedContract",
|
|
94
|
+
method: "getData",
|
|
95
|
+
...options,
|
|
96
|
+
})
|
|
97
|
+
).rejects.toThrowError("Invalid call type: invalid. Use \"read\" or \"write\".");
|
|
98
|
+
|
|
99
|
+
expect(mockClient.readContract).not.toHaveBeenCalled();
|
|
100
|
+
expect(mockClient.writeContract).not.toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("handles errors during readContract", async () => {
|
|
104
|
+
const options: CallOptions = {
|
|
105
|
+
args: [1],
|
|
106
|
+
type: "read",
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
vi.mocked(mockClient.readContract).mockRejectedValue(
|
|
110
|
+
new Error("Mocked read error")
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
await expect(
|
|
114
|
+
caller.call({
|
|
115
|
+
contractAddress: "0xMockedContract",
|
|
116
|
+
method: "getData",
|
|
117
|
+
...options,
|
|
118
|
+
})
|
|
119
|
+
).rejects.toThrowError("Mocked read error");
|
|
120
|
+
|
|
121
|
+
expect(mockClient.readContract).toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("handles errors during writeContract", async () => {
|
|
125
|
+
const options: CallOptions = {
|
|
126
|
+
args: [1],
|
|
127
|
+
type: "write",
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
vi.mocked(mockClient.writeContract).mockRejectedValue(
|
|
131
|
+
new Error("Mocked write error")
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
await expect(
|
|
135
|
+
caller.call({
|
|
136
|
+
contractAddress: "0xMockedContract",
|
|
137
|
+
method: "updateData",
|
|
138
|
+
...options,
|
|
139
|
+
})
|
|
140
|
+
).rejects.toThrowError("Mocked write error");
|
|
141
|
+
|
|
142
|
+
expect(mockClient.writeContract).toHaveBeenCalled();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -89,7 +89,7 @@ describe("KeypairCreator", () => {
|
|
|
89
89
|
|
|
90
90
|
test("overwrites the file if overwrite is true", () => {
|
|
91
91
|
const consoleLogSpy = vi.spyOn(console, "log");
|
|
92
|
-
vi.mocked(existsSync).mockReturnValue(true);
|
|
92
|
+
vi.mocked(existsSync).mockReturnValue(true);
|
|
93
93
|
const options = { output: "keypair.json", overwrite: true };
|
|
94
94
|
|
|
95
95
|
keypairCreator.createKeypairAction(options);
|