Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions src/commands/contracts/call.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import { createClient, createAccount } from "genlayer-js";
import { simulator } from "genlayer-js/chains";
import type { GenLayerClient } from "genlayer-js/types";
import { getPrivateKey } from "../../lib/accounts/getPrivateKey";
import { BaseAction } from "../../lib/actions/BaseAction";

export interface CallOptions {
args: any[];
}

export class CallAction extends BaseAction{
private genlayerClient: GenLayerClient<typeof simulator>;

constructor() {
super();
this.genlayerClient = createClient({
chain: simulator,
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
account: createAccount(getPrivateKey() as any),
});
}

async call({
Expand All @@ -29,9 +20,10 @@ export class CallAction extends BaseAction{
method: string;
args: any[];
}): Promise<void> {
const client = await this.getClient();
this.startSpinner(`Calling method ${method} on contract at ${contractAddress}...`);

const contractSchema = await this.genlayerClient.getContractSchema(contractAddress);
const contractSchema = await client.getContractSchema(contractAddress);

if(!contractSchema.methods.hasOwnProperty(method)){
this.failSpinner(`method ${method} not found.`);
Expand All @@ -50,7 +42,8 @@ export class CallAction extends BaseAction{

private async executeRead(contractAddress: string, method: string, args: any[]): Promise<void> {
try {
const result = await this.genlayerClient.readContract({
const client = await this.getClient();
const result = await client.readContract({
address: contractAddress as any,
functionName: method,
args,
Expand All @@ -63,13 +56,14 @@ export class CallAction extends BaseAction{

private async executeWrite(contractAddress: string, method: string, args: any[]): Promise<void> {
try {
const hash = await this.genlayerClient.writeContract({
const client = await this.getClient();
const hash = await client.writeContract({
address: contractAddress as any,
functionName: method,
args,
value: 0n,
});
const result = await this.genlayerClient.waitForTransactionReceipt({
const result = await client.waitForTransactionReceipt({
hash,
retries: 15,
interval: 2000,
Expand Down
18 changes: 6 additions & 12 deletions src/commands/contracts/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import fs from "fs";
import path from "path";
import { createClient, createAccount } from "genlayer-js";
import { simulator } from "genlayer-js/chains";
import type { GenLayerClient } from "genlayer-js/types";
import { getPrivateKey } from "../../lib/accounts/getPrivateKey";
import { BaseAction } from "../../lib/actions/BaseAction";
import { pathToFileURL } from "url";
import { TransactionStatus } from "genlayer-js/types";
Expand All @@ -15,16 +13,10 @@ export interface DeployOptions {
}

export class DeployAction extends BaseAction {
private genlayerClient: GenLayerClient<typeof simulator>;
private readonly deployDir = path.resolve(process.cwd(), "deploy");

constructor() {
super();
this.genlayerClient = createClient({
chain: simulator,
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
account: createAccount(getPrivateKey() as any),
});
}

private readContractCode(contractPath: string): string {
Expand Down Expand Up @@ -63,7 +55,8 @@ export class DeployAction extends BaseAction {
this.failSpinner(`No "default" function found in: ${filePath}`);
return
}
await module.default(this.genlayerClient);
const client = await this.getClient();
await module.default(client);
this.succeedSpinner(`Successfully executed: ${filePath}`);
} catch (error) {
this.failSpinner(`Error executing: ${filePath}`, error);
Expand Down Expand Up @@ -112,8 +105,9 @@ export class DeployAction extends BaseAction {

async deploy(options: DeployOptions): Promise<void> {
try {
const client = await this.getClient();
this.startSpinner("Setting up the deployment environment...");
await this.genlayerClient.initializeConsensusSmartContract();
await client.initializeConsensusSmartContract();

if (!options.contract) {
this.failSpinner("No contract specified for deployment.");
Expand All @@ -133,8 +127,8 @@ export class DeployAction extends BaseAction {
this.setSpinnerText("Starting contract deployment...");
this.log("Deployment Parameters:", deployParams);

const hash = (await this.genlayerClient.deployContract(deployParams)) as any;
const result = await this.genlayerClient.waitForTransactionReceipt({
const hash = (await client.deployContract(deployParams)) as any;
const result = await client.waitForTransactionReceipt({
hash,
retries: 15,
interval: 2000,
Expand Down
30 changes: 5 additions & 25 deletions src/commands/keygen/create.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,22 @@
import { writeFileSync, existsSync } from "fs";
import { ethers } from "ethers";
import { BaseAction } from "../../lib/actions/BaseAction";

export interface CreateKeypairOptions {
output: string;
overwrite: boolean;
}

export class KeypairCreator extends BaseAction{

export class KeypairCreator extends BaseAction {
constructor() {
super()
super();
}

createKeypairAction(options: CreateKeypairOptions) {
try {
this.startSpinner(`Creating keypair...`);
const outputPath = this.getFilePath(options.output);

if(existsSync(outputPath) && !options.overwrite) {
this.failSpinner(
`The file at ${outputPath} already exists. Use the '--overwrite' option to replace it.`
);
return;
}

const wallet = ethers.Wallet.createRandom();
const keypairData = {
address: wallet.address,
privateKey: wallet.privateKey,
};

writeFileSync(outputPath, JSON.stringify(keypairData, null, 2));

this.writeConfig('keyPairPath', outputPath);
this.succeedSpinner(`Keypair successfully created and saved to: ${outputPath}`);
this.keypairManager.createKeypair(options.output, options.overwrite);
this.succeedSpinner(`Keypair successfully created and saved to: ${options.output}`);
} catch (error) {
this.failSpinner("Failed to generate keypair:", error);
this.failSpinner("Failed to generate keypair", error);
}
}
}
43 changes: 43 additions & 0 deletions src/lib/accounts/KeypairManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { writeFileSync, existsSync, readFileSync } from "fs";
import { ethers } from "ethers";
import path from "path";
import { ConfigFileManager } from "../config/ConfigFileManager";

export class KeypairManager extends ConfigFileManager {
constructor() {
super();
}

getPrivateKey(): string | undefined {
const keypairPath = this.getConfigByKey("keyPairPath");

if (!keypairPath || !existsSync(keypairPath)) {
return ""
}

const keypairData = JSON.parse(readFileSync(keypairPath, "utf-8"));

if (!keypairData.privateKey) {
return ""
}

return keypairData.privateKey;
}

createKeypair(outputPath = "./keypair.json", overwrite: boolean = false): void {
const finalOutputPath = this.getFilePath(outputPath);

if(existsSync(finalOutputPath) && !overwrite) {
throw new Error(`The file at ${finalOutputPath} already exists. Use the '--overwrite' option to replace it.`);
}

const wallet = ethers.Wallet.createRandom();
const keypairData = {
address: wallet.address,
privateKey: wallet.privateKey,
};

writeFileSync(finalOutputPath, JSON.stringify(keypairData, null, 2));
this.writeConfig('keyPairPath', finalOutputPath);
}
}
21 changes: 0 additions & 21 deletions src/lib/accounts/getPrivateKey.ts

This file was deleted.

29 changes: 28 additions & 1 deletion src/lib/actions/BaseAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,41 @@ import { ConfigFileManager } from "../../lib/config/ConfigFileManager";
import ora, { Ora } from "ora";
import chalk from "chalk";
import inquirer from "inquirer";

import { KeypairManager } from "../accounts/KeypairManager";
import { createClient, createAccount } from "genlayer-js";
import { localnet } from "genlayer-js/chains";
import type { GenLayerClient } from "genlayer-js/types";

export class BaseAction extends ConfigFileManager {
protected keypairManager: KeypairManager;
private spinner: Ora;
private _genlayerClient: GenLayerClient<typeof localnet> | null = null;

constructor() {
super()
this.spinner = ora({ text: "", spinner: "dots" });
this.keypairManager = new KeypairManager();
}

protected async getClient(): Promise<GenLayerClient<typeof localnet>> {
if (!this._genlayerClient) {
this._genlayerClient = createClient({
chain: localnet,
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
account: createAccount(await this.getPrivateKey() as any),
});
}
return this._genlayerClient;
}

protected async getPrivateKey() {
const privateKey = this.keypairManager.getPrivateKey();
if (privateKey) {
return privateKey;
}
await this.confirmPrompt("Keypair file not found. Would you like to create a new keypair?");
this.keypairManager.createKeypair();
return this.keypairManager.getPrivateKey();
}

protected async confirmPrompt(message: string): Promise<void> {
Expand Down
4 changes: 1 addition & 3 deletions tests/actions/call.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
import { createClient, createAccount } from "genlayer-js";
import { CallAction } from "../../src/commands/contracts/call";
import { getPrivateKey } from "../../src/lib/accounts/getPrivateKey";

vi.mock("genlayer-js");
vi.mock("../../src/lib/accounts/getPrivateKey");

describe("CallAction", () => {
let callActions: CallAction;
Expand All @@ -21,8 +19,8 @@ describe("CallAction", () => {
vi.clearAllMocks();
vi.mocked(createClient).mockReturnValue(mockClient as any);
vi.mocked(createAccount).mockReturnValue({ privateKey: mockPrivateKey } as any);
vi.mocked(getPrivateKey).mockReturnValue(mockPrivateKey);
callActions = new CallAction();
vi.spyOn(callActions as any, "getPrivateKey").mockResolvedValue(mockPrivateKey);

vi.spyOn(callActions as any, "startSpinner").mockImplementation(() => {});
vi.spyOn(callActions as any, "succeedSpinner").mockImplementation(() => {});
Expand Down
Loading