From d4a91631c2af80aa836d4a5bc56015b5743a95bc Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Sat, 30 Dec 2023 00:24:20 +0200 Subject: [PATCH 01/33] Update SwankyConfig, make local and system configs --- src/commands/account/create.ts | 4 +- src/commands/account/default.ts | 64 +++++++++++++++++++++++++++++++ src/commands/account/list.ts | 12 +++++- src/commands/check/index.ts | 7 ++-- src/commands/contract/deploy.ts | 38 +++++++++++++++--- src/commands/contract/new.ts | 3 +- src/commands/init/index.ts | 20 ++++++++-- src/commands/node/install.ts | 4 +- src/lib/command-utils.ts | 21 +++++++++- src/lib/swankyCommand.ts | 68 +++++++++++++++++++++++++++------ src/types/index.ts | 15 ++++++++ 11 files changed, 221 insertions(+), 35 deletions(-) create mode 100644 src/commands/account/default.ts diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 5c4fc4c4..a3990ef6 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -59,6 +59,7 @@ export class CreateAccount extends SwankyCommand { const accountData: AccountData = { mnemonic: "", isDev, + default: false, alias: (await inquirer.prompt([{ type: "input", message: "Enter alias: ", name: "alias" }])) .alias, address: new ChainAccount(tmpMnemonic).pair.address, @@ -76,8 +77,7 @@ export class CreateAccount extends SwankyCommand { } this.swankyConfig.accounts.push(accountData); - - await this.storeConfig(); + await this.storeSystemConfig(); this.log( `${chalk.greenBright("✔")} Account with alias ${chalk.yellowBright( diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts new file mode 100644 index 00000000..797acdea --- /dev/null +++ b/src/commands/account/default.ts @@ -0,0 +1,64 @@ +import { Args } from "@oclif/core"; +import chalk from "chalk"; +import { AccountData } from "../../types/index.js"; +import inquirer from "inquirer"; +import { SwankyCommand } from "../../lib/swankyCommand.js"; +import { ConfigError } from "../../lib/errors.js"; +export class DefaultAccount extends SwankyCommand { + static description = "Set default account to use"; + + static args = { + accountAlias: Args.string({ + name: "accountAlias", + required: false, + description: "Alias of account to be used as default", + }), + }; + + async run(): Promise { + const { args } = await this.parse(DefaultAccount); + + let defaultAccount = ""; + + if(args.accountAlias) { + const accountData = this.swankyConfig.accounts.find( + (account: AccountData) => account.alias === args.accountAlias + ); + if (!accountData) { + throw new ConfigError("Provided account alias not found in swanky.config.json"); + } + defaultAccount = accountData.alias; + } else { + inquirer.prompt([ + { + type: "list", + name: "defaultAccount", + message: "Select default account", + choices: this.swankyConfig.accounts.map((account: AccountData) => { + return { + name: `${account.alias} (${account.address})`, + value: account.alias, + }; + }), + }, + ]).then((answers) => { + defaultAccount = answers.defaultAccount; + }); + } + this.defaultAccount = defaultAccount; + this.swankyConfig.accounts = this.swankyConfig.accounts.map((account: AccountData) => { + if (account.alias === defaultAccount) { + return { + ...account, + default: true, + }; + } + return { + ...account, + default: false, + }; + }); + await this.storeSystemConfig(); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(defaultAccount)}`)); + } +} diff --git a/src/commands/account/list.ts b/src/commands/account/list.ts index a7c294bd..ea2cd5bb 100644 --- a/src/commands/account/list.ts +++ b/src/commands/account/list.ts @@ -9,7 +9,17 @@ export class ListAccounts extends SwankyCommand { this.log(`${chalk.greenBright("✔")} Stored dev accounts:`); for (const account of this.swankyConfig.accounts) { - this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`); + if(account.isDev){ + this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`); + } + } + + this.log(`${chalk.greenBright("✔")} Stored prod accounts:`); + + for (const account of this.swankyConfig.accounts) { + if(!account.isDev){ + this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`); + } } } } diff --git a/src/commands/check/index.ts b/src/commands/check/index.ts index 9d1d27fa..598b6b9b 100644 --- a/src/commands/check/index.ts +++ b/src/commands/check/index.ts @@ -1,7 +1,7 @@ import { Listr } from "listr2"; import { commandStdoutOrNull } from "../../lib/index.js"; import { SwankyConfig } from "../../types/index.js"; -import { pathExistsSync, readJSON } from "fs-extra/esm"; +import { pathExistsSync} from "fs-extra/esm"; import { readFileSync } from "fs"; import path from "node:path"; import TOML from "@iarna/toml"; @@ -62,10 +62,9 @@ export default class Check extends SwankyCommand { { title: "Read ink dependencies", task: async (ctx) => { - const swankyConfig = await readJSON("swanky.config.json"); - ctx.swankyConfig = swankyConfig; + ctx.swankyConfig = this.swankyConfig; - for (const contract in swankyConfig.contracts) { + for (const contract in ctx.swankyConfig.contracts) { const tomlPath = path.resolve(`contracts/${contract}/Cargo.toml`); const doesCargoTomlExist = pathExistsSync(tomlPath); if (!doesCargoTomlExist) { diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 7b2e5482..b550c961 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -15,7 +15,7 @@ export class DeployContract extends SwankyCommand { static flags = { account: Flags.string({ - required: true, + default: "", description: "Alias of account to be used", }), gas: Flags.integer({ @@ -70,13 +70,43 @@ export class DeployContract extends SwankyCommand { ); } + if(!flags.account && !this.defaultAccount) { + throw new ConfigError("No default account set. Please set one or provide an account alias with --account"); + } + + const accountAlias = flags.account ?? this.defaultAccount; + const accountData = this.swankyConfig.accounts.find( - (account: AccountData) => account.alias === flags.account + (account: AccountData) => account.alias === accountAlias ); if (!accountData) { throw new ConfigError("Provided account alias not found in swanky.config.json"); } + if (accountData.isDev && flags.network !== "local") { + throw new ConfigError( + `Account ${accountAlias} is a DEV account and can only be used with local network` + ); + } + + if(!this.defaultAccount) + { + this.defaultAccount = accountData.alias; + this.swankyConfig.accounts = this.swankyConfig.accounts.map((account: AccountData) => { + if (account.alias === accountData.alias) { + return { + ...account, + default: true, + }; + } + return { + ...account, + default: false, + }; + }); + await this.storeSystemConfig(); + } + const mnemonic = accountData.isDev ? (accountData.mnemonic as string) : decrypt( @@ -138,9 +168,7 @@ export class DeployContract extends SwankyCommand { }, ]; - await writeJSON(path.resolve("swanky.config.json"), this.swankyConfig, { - spaces: 2, - }); + await this.storeLocalConfig(process.cwd()); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index 0936663f..de060149 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -102,8 +102,7 @@ export class NewContract extends SwankyCommand { deployments: [], }; - await writeJSON(path.resolve("swanky.config.json"), this.swankyConfig, { spaces: 2 }); - }, "Writing config"); + await this.storeLocalConfig(process.cwd())}, "Writing config"); this.log("😎 New contract successfully generated! 😎"); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index 45177372..d4117030 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -175,12 +175,14 @@ export class Init extends SwankyCommand { { alias: "alice", mnemonic: "//Alice", + default: true, isDev: true, address: new ChainAccount("//Alice").pair.address, }, { alias: "bob", mnemonic: "//Bob", + default: false, isDev: true, address: new ChainAccount("//Bob").pair.address, }, @@ -192,10 +194,20 @@ export class Init extends SwankyCommand { }); this.taskQueue.push({ - task: () => - writeJSON(path.resolve(this.projectPath, "swanky.config.json"), this.configBuilder, { - spaces: 2, - }), + task: () => { + console.log("\nSwanky config:", this.swankyConfig) + if (Object.keys(this.swankyConfig.networks).length === 0 || this.swankyConfig.accounts.length === 0) { + this.swankyConfig = this.configBuilder as SwankyConfig; + console.log("\n1\n"); + } else { + this.swankyConfig.node = this.configBuilder.node!; + this.swankyConfig.contracts = this.configBuilder.contracts!; + console.log("\n2\n"); + } + console.log("\nFinalised Swanky config:", this.swankyConfig) + this.storeLocalConfig(this.projectPath); + this.storeSystemConfig(); + }, args: [], runningMessage: "Writing config", }); diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 8d9beb5e..7b8d5f0f 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -38,9 +38,7 @@ export class InstallNode extends SwankyCommand { await this.spinner.runCommand( () => - writeJSON(path.resolve(projectPath, "swanky.config.json"), this.swankyConfig, { - spaces: 2, - }), + this.storeLocalConfig(projectPath), "Updating swanky config" ); diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index 5cffd073..de164b56 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -2,8 +2,9 @@ import { execaCommand } from "execa"; import { copy, emptyDir, ensureDir, readJSON } from "fs-extra/esm"; import path from "node:path"; import { DEFAULT_NETWORK_URL, ARTIFACTS_PATH, TYPED_CONTRACTS_PATH } from "./consts.js"; -import { SwankyConfig } from "../types/index.js"; +import { SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; import { ConfigError, FileError, InputError } from "./errors.js"; +import { userInfo } from "os"; export async function commandStdoutOrNull(command: string): Promise { try { @@ -14,7 +15,7 @@ export async function commandStdoutOrNull(command: string): Promise { +export async function getSwankyLocalConfig(): Promise { try { const config = await readJSON("swanky.config.json"); return config; @@ -23,6 +24,22 @@ export async function getSwankyConfig(): Promise { } } +export async function getSwankySystemConfig(): Promise { + try { + const config = await readJSON(findSwankySystemConfigPath() + "/swanky.config.json"); + return config; + } catch (cause) { + throw new ConfigError("Error reading swanky.config.json in system directory!", { cause }); + } +} + +export function findSwankySystemConfigPath(): string { + const homeDir = userInfo().homedir; + const amountOfDirectories = process.cwd().split("/").length - homeDir.split("/").length; + const configPath = "../".repeat(amountOfDirectories)+"swanky"; + return configPath; +} + export function resolveNetworkUrl(config: SwankyConfig, networkName: string): string { if (networkName === "") { return DEFAULT_NETWORK_URL; diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index b2d6c625..eec06d86 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -1,10 +1,12 @@ import { Command, Flags, Interfaces } from "@oclif/core"; -import { getSwankyConfig, Spinner } from "./index.js"; -import { SwankyConfig } from "../types/index.js"; +import { getSwankySystemConfig, getSwankyLocalConfig, Spinner, findSwankySystemConfigPath } from "./index.js"; +import { AccountData, SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; -import { BaseError, ConfigError, UnknownError } from "./errors.js"; +import {mkdirSync, existsSync} from "fs"; +import { BaseError, UnknownError } from "./errors.js"; import { swankyLogger } from "./logger.js"; import { Logger } from "winston"; +import path from "node:path"; export type Flags = Interfaces.InferredFlags< (typeof SwankyCommand)["baseFlags"] & T["flags"] >; @@ -16,6 +18,7 @@ export abstract class SwankyCommand extends Command { protected spinner!: Spinner; protected swankyConfig!: SwankyConfig; protected logger!: Logger; + protected defaultAccount!: string; protected flags!: Flags; protected args!: Args; @@ -34,27 +37,68 @@ export abstract class SwankyCommand extends Command { this.args = args as Args; this.logger = swankyLogger; + this.swankyConfig = { + node: { + polkadotPalletVersions: "", + localPath: "", + supportedInk: "", + }, + contracts: {}, + accounts: [], + networks: {}, + }; + + try { + const localConfig = await getSwankyLocalConfig(); + this.swankyConfig = { + ...this.swankyConfig, + ...localConfig, + }; + } catch (error) { + this.logger.warn("No local config found") + } + try { - this.swankyConfig = await getSwankyConfig(); + const systemConfig = await getSwankySystemConfig(); + this.swankyConfig = { + ...this.swankyConfig, + ...systemConfig, + }; } catch (error) { - if ( - error instanceof Error && - error.message.includes("swanky.config.json") && - (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG - ) - throw new ConfigError("Cannot find swanky.config.json", { cause: error }); + this.logger.warn("No system config found") } + this.defaultAccount = this.swankyConfig.accounts.find( + (account: AccountData) => account.default + )?.alias ?? ""; + this.logger.info(`Running command: ${this.ctor.name} Args: ${JSON.stringify(this.args)} Flags: ${JSON.stringify(this.flags)} Full command: ${JSON.stringify(process.argv)}`); } - protected async storeConfig() { - await writeJSON("swanky.config.json", this.swankyConfig, { spaces: 2 }); + protected async storeLocalConfig(projectPath: string) { + const localConfig : SwankyLocalConfig = { + node: this.swankyConfig.node, + contracts: this.swankyConfig.contracts + } + await writeJSON(path.resolve(projectPath, "swanky.config.json"), localConfig, { spaces: 2 }); } + protected async storeSystemConfig() { + const systemConfig : SwankySystemConfig = { + accounts: this.swankyConfig.accounts, + networks: this.swankyConfig.networks + } + + const configPath = findSwankySystemConfigPath(); + + if (!existsSync(path.resolve(configPath))) { + mkdirSync(path.resolve(configPath), { recursive: true }); + } + await writeJSON(configPath + "/swanky.config.json", systemConfig, { spaces: 2 }); + } protected async catch(err: Error & { exitCode?: number }): Promise { // add any custom logic to handle errors from the command // or simply return the parent class error handling diff --git a/src/types/index.ts b/src/types/index.ts index aa13a0df..7bc4c775 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -15,6 +15,7 @@ export interface Encrypted { iv: string; data: string }; export interface AccountData { isDev: boolean; + default: boolean; alias: string; mnemonic: string | Encrypted; address: string; @@ -49,5 +50,19 @@ export interface SwankyConfig { networks: Record } +export interface SwankyLocalConfig { + node: { + polkadotPalletVersions: string; + localPath: string; + supportedInk: string; + }; + contracts: Record | Record; +} + +export interface SwankySystemConfig { + accounts: AccountData[]; + networks: Record +} + export type SupportedPlatforms = "darwin" | "linux"; export type SupportedArch = "arm64" | "x64"; From cb804299d8b7b9eed557c415e659f43fee46003e Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Sat, 30 Dec 2023 00:28:53 +0200 Subject: [PATCH 02/33] Clean up imports --- src/commands/contract/deploy.ts | 2 -- src/commands/contract/new.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index b550c961..475ba931 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -1,6 +1,4 @@ import { Args, Flags } from "@oclif/core"; -import path from "node:path"; -import { writeJSON } from "fs-extra/esm"; import { cryptoWaitReady } from "@polkadot/util-crypto/crypto"; import { resolveNetworkUrl, ChainApi, ChainAccount, decrypt, AbiType } from "../../lib/index.js"; import { AccountData, Encrypted } from "../../types/index.js"; diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index de060149..b6b05f9f 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -1,6 +1,6 @@ import { Args, Flags } from "@oclif/core"; import path from "node:path"; -import { ensureDir, pathExists, writeJSON } from "fs-extra/esm"; +import { ensureDir, pathExists } from "fs-extra/esm"; import { checkCliDependencies, copyContractTemplateFiles, From 356ad63097948a82b3f8f30d8de523c6ab337ec1 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Sat, 30 Dec 2023 00:31:31 +0200 Subject: [PATCH 03/33] Clean up imports --- src/commands/node/install.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 7b8d5f0f..a2b38aec 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -2,8 +2,6 @@ import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ux } from "@oclif/core"; import { downloadNode, swankyNode } from "../../lib/index.js"; import path from "node:path"; -import { writeJSON } from "fs-extra/esm"; - export class InstallNode extends SwankyCommand { static description = "Install swanky node binary"; From 9b264a7c37e701f03d19b39aa5ca3d53e0cfdc14 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Tue, 2 Jan 2024 12:58:50 +0200 Subject: [PATCH 04/33] Fix default account feature --- src/commands/account/create.ts | 4 +++- src/commands/account/default.ts | 23 ++++------------------- src/commands/account/list.ts | 26 ++++++++++++++++++-------- src/commands/contract/deploy.ts | 20 ++++---------------- src/commands/init/index.ts | 8 ++------ src/lib/contractCall.ts | 14 ++++++++++++-- src/lib/swankyCommand.ts | 11 ++++------- src/types/index.ts | 5 +++-- 8 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index a3990ef6..a240e2f0 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -59,7 +59,6 @@ export class CreateAccount extends SwankyCommand { const accountData: AccountData = { mnemonic: "", isDev, - default: false, alias: (await inquirer.prompt([{ type: "input", message: "Enter alias: ", name: "alias" }])) .alias, address: new ChainAccount(tmpMnemonic).pair.address, @@ -77,6 +76,9 @@ export class CreateAccount extends SwankyCommand { } this.swankyConfig.accounts.push(accountData); + if(this.swankyConfig.defaultAccount === null) { + this.swankyConfig.defaultAccount = accountData.alias; + } await this.storeSystemConfig(); this.log( diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 797acdea..0c2a49e3 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -18,8 +18,6 @@ export class DefaultAccount extends SwankyCommand { async run(): Promise { const { args } = await this.parse(DefaultAccount); - let defaultAccount = ""; - if(args.accountAlias) { const accountData = this.swankyConfig.accounts.find( (account: AccountData) => account.alias === args.accountAlias @@ -27,9 +25,9 @@ export class DefaultAccount extends SwankyCommand { if (!accountData) { throw new ConfigError("Provided account alias not found in swanky.config.json"); } - defaultAccount = accountData.alias; + this.swankyConfig.defaultAccount = accountData.alias; } else { - inquirer.prompt([ + await inquirer.prompt([ { type: "list", name: "defaultAccount", @@ -42,23 +40,10 @@ export class DefaultAccount extends SwankyCommand { }), }, ]).then((answers) => { - defaultAccount = answers.defaultAccount; + this.swankyConfig.defaultAccount = answers.defaultAccount; }); } - this.defaultAccount = defaultAccount; - this.swankyConfig.accounts = this.swankyConfig.accounts.map((account: AccountData) => { - if (account.alias === defaultAccount) { - return { - ...account, - default: true, - }; - } - return { - ...account, - default: false, - }; - }); await this.storeSystemConfig(); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(defaultAccount)}`)); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } } diff --git a/src/commands/account/list.ts b/src/commands/account/list.ts index ea2cd5bb..08bfb4c6 100644 --- a/src/commands/account/list.ts +++ b/src/commands/account/list.ts @@ -6,19 +6,29 @@ export class ListAccounts extends SwankyCommand { static aliases = [`account:ls`]; async run(): Promise { - this.log(`${chalk.greenBright("✔")} Stored dev accounts:`); + const countOfDevAccounts = this.swankyConfig.accounts.filter((account) => account.isDev).length; - for (const account of this.swankyConfig.accounts) { - if(account.isDev){ - this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`); + if(countOfDevAccounts !== 0) { + this.log(`${chalk.greenBright("✔")} Stored dev accounts:`); + + for (const account of this.swankyConfig.accounts) { + if(account.isDev){ + this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias} \ +${chalk.yellowBright("Address: ")} ${account.address} ${this.swankyConfig.defaultAccount === account.alias ? chalk.greenBright("<- Default") : ""}`); + } } } - this.log(`${chalk.greenBright("✔")} Stored prod accounts:`); + const countOfProdAccounts = this.swankyConfig.accounts.length - countOfDevAccounts; + + if(countOfProdAccounts !== 0) { + this.log(`${chalk.greenBright("✔")} Stored prod accounts:`); - for (const account of this.swankyConfig.accounts) { - if(!account.isDev){ - this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`); + for (const account of this.swankyConfig.accounts) { + if(!account.isDev){ + this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias} \ +${chalk.yellowBright("Address: ")} ${account.address} ${this.swankyConfig.defaultAccount === account.alias ? chalk.greenBright("<- Default") : ""}`); + } } } } diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 475ba931..831dbce4 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -68,11 +68,11 @@ export class DeployContract extends SwankyCommand { ); } - if(!flags.account && !this.defaultAccount) { + if(!flags.account && this.swankyConfig.defaultAccount === null) { throw new ConfigError("No default account set. Please set one or provide an account alias with --account"); } - const accountAlias = flags.account ?? this.defaultAccount; + const accountAlias = flags.account ?? this.swankyConfig.defaultAccount; const accountData = this.swankyConfig.accounts.find( (account: AccountData) => account.alias === accountAlias @@ -87,21 +87,9 @@ export class DeployContract extends SwankyCommand { ); } - if(!this.defaultAccount) + if(this.swankyConfig.defaultAccount === null) { - this.defaultAccount = accountData.alias; - this.swankyConfig.accounts = this.swankyConfig.accounts.map((account: AccountData) => { - if (account.alias === accountData.alias) { - return { - ...account, - default: true, - }; - } - return { - ...account, - default: false, - }; - }); + this.swankyConfig.defaultAccount = accountAlias; await this.storeSystemConfig(); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index d4117030..2e4e5591 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -175,19 +175,19 @@ export class Init extends SwankyCommand { { alias: "alice", mnemonic: "//Alice", - default: true, isDev: true, address: new ChainAccount("//Alice").pair.address, }, { alias: "bob", mnemonic: "//Bob", - default: false, isDev: true, address: new ChainAccount("//Bob").pair.address, }, ]; + this.configBuilder.defaultAccount = "alice"; + Object.keys(this.configBuilder.contracts!).forEach(async (contractName) => { await ensureDir(path.resolve(this.projectPath, "artifacts", contractName)); await ensureDir(path.resolve(this.projectPath, "tests", contractName)); @@ -195,16 +195,12 @@ export class Init extends SwankyCommand { this.taskQueue.push({ task: () => { - console.log("\nSwanky config:", this.swankyConfig) if (Object.keys(this.swankyConfig.networks).length === 0 || this.swankyConfig.accounts.length === 0) { this.swankyConfig = this.configBuilder as SwankyConfig; - console.log("\n1\n"); } else { this.swankyConfig.node = this.configBuilder.node!; this.swankyConfig.contracts = this.configBuilder.contracts!; - console.log("\n2\n"); } - console.log("\nFinalised Swanky config:", this.swankyConfig) this.storeLocalConfig(this.projectPath); this.storeSystemConfig(); }, diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index 246e97d0..fafbd2d6 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -77,11 +77,21 @@ export abstract class ContractCall extends SwankyComma this.deploymentInfo = deploymentData; + if(!flags.account && this.swankyConfig.defaultAccount === null) { + throw new ConfigError("No default account set in swanky.config.json and no account provided"); + } + + const accountAlias = flags.account ?? this.swankyConfig.defaultAccount; + const accountData = this.swankyConfig.accounts.find( - (account: AccountData) => account.alias === flags.account || "alice" + (account: AccountData) => account.alias === accountAlias ); if (!accountData) { - throw new ConfigError("Provided account alias not found in swanky.config.json"); + throw new ConfigError(`Provided account alias(${chalk.redBright(accountAlias)}) not found in swanky.config.json`); + } + + if(accountData.isDev && (flags.network !== "local" || !flags.network)) { + throw new ConfigError(`Account ${chalk.redBright(accountAlias)} is a dev account and can only be used on the local network`); } const networkUrl = resolveNetworkUrl(this.swankyConfig, flags.network ?? ""); diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index eec06d86..fa7a6709 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -1,8 +1,8 @@ import { Command, Flags, Interfaces } from "@oclif/core"; import { getSwankySystemConfig, getSwankyLocalConfig, Spinner, findSwankySystemConfigPath } from "./index.js"; -import { AccountData, SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; +import { SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; -import {mkdirSync, existsSync} from "fs"; +import { mkdirSync, existsSync } from "fs"; import { BaseError, UnknownError } from "./errors.js"; import { swankyLogger } from "./logger.js"; import { Logger } from "winston"; @@ -18,7 +18,6 @@ export abstract class SwankyCommand extends Command { protected spinner!: Spinner; protected swankyConfig!: SwankyConfig; protected logger!: Logger; - protected defaultAccount!: string; protected flags!: Flags; protected args!: Args; @@ -44,6 +43,7 @@ export abstract class SwankyCommand extends Command { supportedInk: "", }, contracts: {}, + defaultAccount: null, accounts: [], networks: {}, }; @@ -68,10 +68,6 @@ export abstract class SwankyCommand extends Command { this.logger.warn("No system config found") } - this.defaultAccount = this.swankyConfig.accounts.find( - (account: AccountData) => account.default - )?.alias ?? ""; - this.logger.info(`Running command: ${this.ctor.name} Args: ${JSON.stringify(this.args)} Flags: ${JSON.stringify(this.flags)} @@ -88,6 +84,7 @@ export abstract class SwankyCommand extends Command { protected async storeSystemConfig() { const systemConfig : SwankySystemConfig = { + defaultAccount: this.swankyConfig.defaultAccount, accounts: this.swankyConfig.accounts, networks: this.swankyConfig.networks } diff --git a/src/types/index.ts b/src/types/index.ts index 7bc4c775..c8883a59 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -11,11 +11,10 @@ export interface ChainProperty { export type ExtrinsicPayload = SubmittableExtrinsic<"promise">; -export interface Encrypted { iv: string; data: string }; +export interface Encrypted { iv: string; data: string } export interface AccountData { isDev: boolean; - default: boolean; alias: string; mnemonic: string | Encrypted; address: string; @@ -45,6 +44,7 @@ export interface SwankyConfig { localPath: string; supportedInk: string; }; + defaultAccount: string | null; accounts: AccountData[]; contracts: Record | Record; networks: Record @@ -60,6 +60,7 @@ export interface SwankyLocalConfig { } export interface SwankySystemConfig { + defaultAccount: string | null; accounts: AccountData[]; networks: Record } From b70851dfde1e6da6453dc6b59aebd6535cda1abb Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Wed, 24 Jan 2024 20:11:38 +0200 Subject: [PATCH 05/33] Fixes --- src/commands/account/create.ts | 15 +++++++-- src/commands/account/default.ts | 23 +++++++++++-- src/commands/check/index.ts | 20 ++++++++--- src/commands/contract/deploy.ts | 14 ++++---- src/commands/contract/new.ts | 2 +- src/commands/init/index.ts | 59 ++++----------------------------- src/commands/node/install.ts | 2 +- src/lib/command-utils.ts | 46 ++++++++++++++++++++++--- src/lib/consts.ts | 2 ++ src/lib/contractCall.ts | 6 ++-- src/lib/swankyCommand.ts | 52 +++++++++++++++-------------- src/types/index.ts | 14 +------- 12 files changed, 139 insertions(+), 116 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index a240e2f0..0ba54ac9 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -1,6 +1,6 @@ import { Flags } from "@oclif/core"; import chalk from "chalk"; -import { ChainAccount, encrypt } from "../../lib/index.js"; +import { ChainAccount, encrypt, isLocalConfigCheck } from "../../lib/index.js"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; @@ -8,6 +8,9 @@ export class CreateAccount extends SwankyCommand { static description = "Create a new dev account in config"; static flags = { + global: Flags.boolean({ + description: "Create account globally", + }), generate: Flags.boolean({ char: "g", }), @@ -79,7 +82,15 @@ export class CreateAccount extends SwankyCommand { if(this.swankyConfig.defaultAccount === null) { this.swankyConfig.defaultAccount = accountData.alias; } - await this.storeSystemConfig(); + + if(flags.global) { + await this.storeSystemConfig(); + } + else if(isLocalConfigCheck()) { + await this.storeConfig(process.cwd()); + } else { + throw new Error("Cannot store account to config. Please run this command in a swanky project directory"); + } this.log( `${chalk.greenBright("✔")} Account with alias ${chalk.yellowBright( diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 0c2a49e3..27d90cb1 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -1,12 +1,20 @@ -import { Args } from "@oclif/core"; +import { Args, Flags } from "@oclif/core"; import chalk from "chalk"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError } from "../../lib/errors.js"; +import { isLocalConfigCheck } from "../../lib/index.js"; export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; + static flags = { + global: Flags.boolean({ + char: "g", + description: "Set default account globally", + }), + } + static args = { accountAlias: Args.string({ name: "accountAlias", @@ -16,7 +24,7 @@ export class DefaultAccount extends SwankyCommand { }; async run(): Promise { - const { args } = await this.parse(DefaultAccount); + const { args, flags } = await this.parse(DefaultAccount); if(args.accountAlias) { const accountData = this.swankyConfig.accounts.find( @@ -43,7 +51,16 @@ export class DefaultAccount extends SwankyCommand { this.swankyConfig.defaultAccount = answers.defaultAccount; }); } - await this.storeSystemConfig(); + + if(flags.global) { + await this.storeSystemConfig(); + } + else if(isLocalConfigCheck()) { + await this.storeConfig(process.cwd()); + } else { + throw new Error("Cannot store account to config. Please run this command in a swanky project directory"); + } + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } } diff --git a/src/commands/check/index.ts b/src/commands/check/index.ts index 598b6b9b..2012bacf 100644 --- a/src/commands/check/index.ts +++ b/src/commands/check/index.ts @@ -1,5 +1,5 @@ import { Listr } from "listr2"; -import { commandStdoutOrNull } from "../../lib/index.js"; +import { commandStdoutOrNull, isLocalConfigCheck } from "../../lib/index.js"; import { SwankyConfig } from "../../types/index.js"; import { pathExistsSync} from "fs-extra/esm"; import { readFileSync } from "fs"; @@ -7,6 +7,7 @@ import path from "node:path"; import TOML from "@iarna/toml"; import semver from "semver"; import { SwankyCommand } from "../../lib/swankyCommand.js"; +import { FileError } from "../../lib/errors.js"; interface Ctx { versions: { @@ -60,11 +61,20 @@ export default class Check extends SwankyCommand { }, }, { - title: "Read ink dependencies", + title: "Check Swanky Config", task: async (ctx) => { + if (this.swankyConfig == undefined){ + throw new FileError("Swanky config not found") + } ctx.swankyConfig = this.swankyConfig; - - for (const contract in ctx.swankyConfig.contracts) { + } + }, + { + title: "Read ink dependencies", + enabled: isLocalConfigCheck(), + skip: (ctx) => ctx.swankyConfig == undefined || Object.keys(ctx.swankyConfig.contracts).length == 0, + task: async (ctx) => { + for (const contract in ctx.swankyConfig!.contracts) { const tomlPath = path.resolve(`contracts/${contract}/Cargo.toml`); const doesCargoTomlExist = pathExistsSync(tomlPath); if (!doesCargoTomlExist) { @@ -89,6 +99,8 @@ export default class Check extends SwankyCommand { }, { title: "Verify ink version", + enabled: isLocalConfigCheck(), + skip: (ctx) => ctx.swankyConfig == undefined || Object.keys(ctx.swankyConfig.contracts).length == 0, task: async (ctx) => { const supportedInk = ctx.swankyConfig?.node.supportedInk; diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 831dbce4..84350e0c 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -1,19 +1,20 @@ import { Args, Flags } from "@oclif/core"; import { cryptoWaitReady } from "@polkadot/util-crypto/crypto"; -import { resolveNetworkUrl, ChainApi, ChainAccount, decrypt, AbiType } from "../../lib/index.js"; +import { resolveNetworkUrl, ChainApi, ChainAccount, decrypt, AbiType, ensureAccountIsSet } from "../../lib/index.js"; import { AccountData, Encrypted } from "../../types/index.js"; import inquirer from "inquirer"; import chalk from "chalk"; import { Contract } from "../../lib/contract.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ApiError, ConfigError, FileError } from "../../lib/errors.js"; +import { DEFAULT_ACCOUNT } from "../../lib/consts.js"; export class DeployContract extends SwankyCommand { static description = "Deploy contract to a running node"; static flags = { account: Flags.string({ - default: "", + default: DEFAULT_ACCOUNT, description: "Alias of account to be used", }), gas: Flags.integer({ @@ -30,6 +31,7 @@ export class DeployContract extends SwankyCommand { }), network: Flags.string({ char: "n", + default: "local", description: "Network name to connect to", }), }; @@ -45,6 +47,8 @@ export class DeployContract extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DeployContract); + console.log("flags", flags); + const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( @@ -68,9 +72,7 @@ export class DeployContract extends SwankyCommand { ); } - if(!flags.account && this.swankyConfig.defaultAccount === null) { - throw new ConfigError("No default account set. Please set one or provide an account alias with --account"); - } + ensureAccountIsSet(flags.account, this.swankyConfig); const accountAlias = flags.account ?? this.swankyConfig.defaultAccount; @@ -154,7 +156,7 @@ export class DeployContract extends SwankyCommand { }, ]; - await this.storeLocalConfig(process.cwd()); + await this.storeConfig(process.cwd()); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index b6b05f9f..f8b767fa 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -102,7 +102,7 @@ export class NewContract extends SwankyCommand { deployments: [], }; - await this.storeLocalConfig(process.cwd())}, "Writing config"); + await this.storeConfig(process.cwd())}, "Writing config"); this.log("😎 New contract successfully generated! 😎"); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index 2e4e5591..b1d0eb22 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -13,23 +13,15 @@ import { copyContractTemplateFiles, downloadNode, installDeps, - ChainAccount, processTemplates, swankyNode, getTemplates, } from "../../lib/index.js"; -import { - DEFAULT_ASTAR_NETWORK_URL, - DEFAULT_NETWORK_URL, - DEFAULT_SHIBUYA_NETWORK_URL, - DEFAULT_SHIDEN_NETWORK_URL, -} from "../../lib/consts.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { InputError, UnknownError } from "../../lib/errors.js"; import { GlobEntry, globby } from "globby"; import { merge } from "lodash-es"; import inquirerFuzzyPath from "inquirer-fuzzy-path"; -import { SwankyConfig } from "../../types/index.js"; import chalk from "chalk"; type TaskFunction = (...args: any[]) => any; @@ -93,22 +85,6 @@ export class Init extends SwankyCommand { } projectPath = ""; - configBuilder: Partial = { - node: { - localPath: "", - polkadotPalletVersions: swankyNode.polkadotPalletVersions, - supportedInk: swankyNode.supportedInk, - }, - accounts: [], - networks: { - local: { url: DEFAULT_NETWORK_URL }, - astar: { url: DEFAULT_ASTAR_NETWORK_URL }, - shiden: { url: DEFAULT_SHIDEN_NETWORK_URL }, - shibuya: { url: DEFAULT_SHIBUYA_NETWORK_URL }, - }, - contracts: {}, - }; - taskQueue: Task[] = []; async run(): Promise { @@ -166,42 +142,19 @@ export class Init extends SwankyCommand { args: [this.projectPath, swankyNode, this.spinner], runningMessage: "Downloading Swanky node", callback: (result) => - this.configBuilder.node ? (this.configBuilder.node.localPath = result) : null, + this.swankyConfig.node ? (this.swankyConfig.node.localPath = result) : null, }); } } - this.configBuilder.accounts = [ - { - alias: "alice", - mnemonic: "//Alice", - isDev: true, - address: new ChainAccount("//Alice").pair.address, - }, - { - alias: "bob", - mnemonic: "//Bob", - isDev: true, - address: new ChainAccount("//Bob").pair.address, - }, - ]; - - this.configBuilder.defaultAccount = "alice"; - - Object.keys(this.configBuilder.contracts!).forEach(async (contractName) => { + Object.keys(this.swankyConfig.contracts).forEach(async (contractName) => { await ensureDir(path.resolve(this.projectPath, "artifacts", contractName)); await ensureDir(path.resolve(this.projectPath, "tests", contractName)); }); this.taskQueue.push({ task: () => { - if (Object.keys(this.swankyConfig.networks).length === 0 || this.swankyConfig.accounts.length === 0) { - this.swankyConfig = this.configBuilder as SwankyConfig; - } else { - this.swankyConfig.node = this.configBuilder.node!; - this.swankyConfig.contracts = this.configBuilder.contracts!; - } - this.storeLocalConfig(this.projectPath); + this.storeConfig(this.projectPath); this.storeSystemConfig(); }, args: [], @@ -294,7 +247,7 @@ export class Init extends SwankyCommand { runningMessage: "Processing templates", }); - this.configBuilder.contracts = { + this.swankyConfig.contracts = { [contractName as string]: { name: contractName, moduleName: snakeCase(contractName), @@ -370,10 +323,10 @@ export class Init extends SwankyCommand { }, }); - if (!this.configBuilder.contracts) this.configBuilder.contracts = {}; + if (!this.swankyConfig.contracts) this.swankyConfig.contracts = {}; for (const contract of confirmedCopyList.contracts) { - this.configBuilder.contracts[contract.name] = { + this.swankyConfig.contracts[contract.name] = { name: contract.name, moduleName: contract.moduleName!, deployments: [], diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index a2b38aec..36eac4b9 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -36,7 +36,7 @@ export class InstallNode extends SwankyCommand { await this.spinner.runCommand( () => - this.storeLocalConfig(projectPath), + this.storeConfig(projectPath), "Updating swanky config" ); diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index de164b56..30388e7d 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -1,10 +1,18 @@ import { execaCommand } from "execa"; import { copy, emptyDir, ensureDir, readJSON } from "fs-extra/esm"; import path from "node:path"; -import { DEFAULT_NETWORK_URL, ARTIFACTS_PATH, TYPED_CONTRACTS_PATH } from "./consts.js"; -import { SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; +import { + DEFAULT_NETWORK_URL, + ARTIFACTS_PATH, + TYPED_CONTRACTS_PATH, + DEFAULT_SHIBUYA_NETWORK_URL, + DEFAULT_SHIDEN_NETWORK_URL, DEFAULT_ASTAR_NETWORK_URL, DEFAULT_ACCOUNT, +} from "./consts.js"; +import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; import { ConfigError, FileError, InputError } from "./errors.js"; import { userInfo } from "os"; +import { swankyNode } from "./nodeInfo.js"; +import { existsSync } from "fs"; export async function commandStdoutOrNull(command: string): Promise { try { @@ -15,9 +23,10 @@ export async function commandStdoutOrNull(command: string): Promise { +export async function getSwankyConfig(): Promise { + const configPath = process.env.SWANKY_CONFIG ?? "swanky.config.json"; try { - const config = await readJSON("swanky.config.json"); + const config = await readJSON(configPath); return config; } catch (cause) { throw new InputError("Error reading swanky.config.json in the current directory!", { cause }); @@ -137,3 +146,32 @@ export async function generateTypes(contractName: string) { `npx typechain-polkadot --in ${relativeInputPath} --out ${relativeOutputPath}` ); } +export function ensureAccountIsSet(account: string | undefined, config: SwankyConfig) { + if(!account && config.defaultAccount === null) { + throw new ConfigError("No default account set. Please set one or provide an account alias with --account"); + } +} + +export function buildSwankyConfig() { + return { + node: { + localPath: "", + polkadotPalletVersions: swankyNode.polkadotPalletVersions, + supportedInk: swankyNode.supportedInk, + }, + defaultAccount: DEFAULT_ACCOUNT, + accounts: [], + networks: { + local: { url: DEFAULT_NETWORK_URL }, + astar: { url: DEFAULT_ASTAR_NETWORK_URL }, + shiden: { url: DEFAULT_SHIDEN_NETWORK_URL }, + shibuya: { url: DEFAULT_SHIBUYA_NETWORK_URL }, + }, + contracts: {}, + }; +} + +export function isLocalConfigCheck() { + console.log("process.env.SWANKY_CONFIG", process.env.SWANKY_CONFIG); + return process.env.SWANKY_CONFIG != "" || existsSync(process.cwd() + "/swanky.config.json"); +} \ No newline at end of file diff --git a/src/lib/consts.ts b/src/lib/consts.ts index d48b2b67..90c48ff3 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -3,5 +3,7 @@ export const DEFAULT_ASTAR_NETWORK_URL = "wss://rpc.astar.network"; export const DEFAULT_SHIDEN_NETWORK_URL = "wss://rpc.shiden.astar.network"; export const DEFAULT_SHIBUYA_NETWORK_URL = "wss://shibuya.public.blastapi.io"; +export const DEFAULT_ACCOUNT = "alice"; + export const ARTIFACTS_PATH = "artifacts"; export const TYPED_CONTRACTS_PATH = "typedContracts"; diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index fafbd2d6..a1d56606 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -1,4 +1,4 @@ -import { AbiType, ChainAccount, ChainApi, decrypt, resolveNetworkUrl } from "./index.js"; +import { AbiType, ChainAccount, ChainApi, decrypt, ensureAccountIsSet, resolveNetworkUrl } from "./index.js"; import { AccountData, ContractData, DeploymentData, Encrypted } from "../types/index.js"; import { Args, Command, Flags, Interfaces } from "@oclif/core"; import inquirer from "inquirer"; @@ -77,9 +77,7 @@ export abstract class ContractCall extends SwankyComma this.deploymentInfo = deploymentData; - if(!flags.account && this.swankyConfig.defaultAccount === null) { - throw new ConfigError("No default account set in swanky.config.json and no account provided"); - } + ensureAccountIsSet(flags.account, this.swankyConfig); const accountAlias = flags.account ?? this.swankyConfig.defaultAccount; diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index fa7a6709..bb0f8c3f 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -1,9 +1,15 @@ import { Command, Flags, Interfaces } from "@oclif/core"; -import { getSwankySystemConfig, getSwankyLocalConfig, Spinner, findSwankySystemConfigPath } from "./index.js"; -import { SwankyConfig, SwankyLocalConfig, SwankySystemConfig } from "../types/index.js"; +import { + getSwankySystemConfig, + getSwankyConfig, + Spinner, + findSwankySystemConfigPath, + buildSwankyConfig, +} from "./index.js"; +import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; import { mkdirSync, existsSync } from "fs"; -import { BaseError, UnknownError } from "./errors.js"; +import { BaseError, ConfigError, UnknownError } from "./errors.js"; import { swankyLogger } from "./logger.js"; import { Logger } from "winston"; import path from "node:path"; @@ -36,36 +42,31 @@ export abstract class SwankyCommand extends Command { this.args = args as Args; this.logger = swankyLogger; - this.swankyConfig = { - node: { - polkadotPalletVersions: "", - localPath: "", - supportedInk: "", - }, - contracts: {}, - defaultAccount: null, - accounts: [], - networks: {}, - }; + this.swankyConfig = buildSwankyConfig(); try { - const localConfig = await getSwankyLocalConfig(); + const systemConfig = await getSwankySystemConfig(); this.swankyConfig = { ...this.swankyConfig, - ...localConfig, + ...systemConfig, }; } catch (error) { - this.logger.warn("No local config found") + this.logger.warn("No system config found") } try { - const systemConfig = await getSwankySystemConfig(); + const localConfig = await getSwankyConfig(); this.swankyConfig = { ...this.swankyConfig, - ...systemConfig, + ...localConfig, }; } catch (error) { - this.logger.warn("No system config found") + this.logger.warn("No local config found") + if (error instanceof Error && + error.message.includes("swanky.config.json") && + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG + ) + throw new ConfigError(`Cannot find ${process.env.SWANKY_CONFIG ?? "swanky.config.json"}`, { cause: error }); } this.logger.info(`Running command: ${this.ctor.name} @@ -74,12 +75,12 @@ export abstract class SwankyCommand extends Command { Full command: ${JSON.stringify(process.argv)}`); } - protected async storeLocalConfig(projectPath: string) { - const localConfig : SwankyLocalConfig = { - node: this.swankyConfig.node, - contracts: this.swankyConfig.contracts + protected async storeConfig(projectPath: string) { + const configPath = process.env.SWANKY_CONFIG ?? path.resolve(projectPath, "swanky.config.json"); + const localConfig : SwankyConfig = { + ...this.swankyConfig, } - await writeJSON(path.resolve(projectPath, "swanky.config.json"), localConfig, { spaces: 2 }); + await writeJSON(configPath, localConfig, { spaces: 2 }); } protected async storeSystemConfig() { @@ -105,6 +106,7 @@ export abstract class SwankyCommand extends Command { protected async finally(_: Error | undefined): Promise { // called after run and catch regardless of whether or not the command errored + // console.log("Swanky Config: ", this.swankyConfig); return super.finally(_); } } diff --git a/src/types/index.ts b/src/types/index.ts index c8883a59..e74543b3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -38,19 +38,7 @@ export interface DeploymentData { deployerAlias: string; address: string; } -export interface SwankyConfig { - node: { - polkadotPalletVersions: string; - localPath: string; - supportedInk: string; - }; - defaultAccount: string | null; - accounts: AccountData[]; - contracts: Record | Record; - networks: Record -} - -export interface SwankyLocalConfig { +export interface SwankyConfig extends SwankySystemConfig{ node: { polkadotPalletVersions: string; localPath: string; From 355eb3971a1f40b6b5ff61d8ae990d9626950c3c Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 25 Jan 2024 11:17:31 +0100 Subject: [PATCH 06/33] fix: Swanky config pre-populated in context to remove type assertions --- src/commands/check/index.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/commands/check/index.ts b/src/commands/check/index.ts index 2012bacf..2304f8ad 100644 --- a/src/commands/check/index.ts +++ b/src/commands/check/index.ts @@ -7,7 +7,6 @@ import path from "node:path"; import TOML from "@iarna/toml"; import semver from "semver"; import { SwankyCommand } from "../../lib/swankyCommand.js"; -import { FileError } from "../../lib/errors.js"; interface Ctx { versions: { @@ -20,7 +19,7 @@ interface Ctx { }; contracts: Record>; }; - swankyConfig?: SwankyConfig; + swankyConfig: SwankyConfig; mismatchedVersions?: Record; looseDefinitionDetected: boolean; } @@ -60,21 +59,12 @@ export default class Check extends SwankyCommand { ctx.versions.tools.cargoContract = await commandStdoutOrNull("cargo contract -V"); }, }, - { - title: "Check Swanky Config", - task: async (ctx) => { - if (this.swankyConfig == undefined){ - throw new FileError("Swanky config not found") - } - ctx.swankyConfig = this.swankyConfig; - } - }, { title: "Read ink dependencies", enabled: isLocalConfigCheck(), - skip: (ctx) => ctx.swankyConfig == undefined || Object.keys(ctx.swankyConfig.contracts).length == 0, + skip: (ctx) => Object.keys(ctx.swankyConfig.contracts).length == 0, task: async (ctx) => { - for (const contract in ctx.swankyConfig!.contracts) { + for (const contract in ctx.swankyConfig.contracts) { const tomlPath = path.resolve(`contracts/${contract}/Cargo.toml`); const doesCargoTomlExist = pathExistsSync(tomlPath); if (!doesCargoTomlExist) { @@ -100,14 +90,14 @@ export default class Check extends SwankyCommand { { title: "Verify ink version", enabled: isLocalConfigCheck(), - skip: (ctx) => ctx.swankyConfig == undefined || Object.keys(ctx.swankyConfig.contracts).length == 0, + skip: (ctx) => Object.keys(ctx.swankyConfig.contracts).length == 0, task: async (ctx) => { - const supportedInk = ctx.swankyConfig?.node.supportedInk; + const supportedInk = ctx.swankyConfig.node.supportedInk; const mismatched: Record = {}; Object.entries(ctx.versions.contracts).forEach(([contract, inkPackages]) => { Object.entries(inkPackages).forEach(([inkPackage, version]) => { - if (semver.gt(version, supportedInk!)) { + if (semver.gt(version, supportedInk)) { mismatched[ `${contract}-${inkPackage}` ] = `Version of ${inkPackage} (${version}) in ${contract} is higher than supported ink version (${supportedInk})`; @@ -125,6 +115,7 @@ export default class Check extends SwankyCommand { ]); const context = await tasks.run({ versions: { tools: {}, contracts: {} }, + swankyConfig: this.swankyConfig, looseDefinitionDetected: false, }); console.log(context.versions); From 2e3da705cb00419aa6dc5091700a518c1022c322 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 25 Jan 2024 18:11:20 +0100 Subject: [PATCH 07/33] fix: config update logic fixed for account create & default command --- src/commands/account/create.ts | 23 ++++++++++++++--------- src/commands/account/default.ts | 22 +++++++++++++--------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 0ba54ac9..518fc2e6 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -4,12 +4,13 @@ import { ChainAccount, encrypt, isLocalConfigCheck } from "../../lib/index.js"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; +import { FileError } from "../../lib/errors.js"; export class CreateAccount extends SwankyCommand { static description = "Create a new dev account in config"; static flags = { global: Flags.boolean({ - description: "Create account globally", + description: "Create account globally: stored in both Swanky system and local configs.", }), generate: Flags.boolean({ char: "g", @@ -79,17 +80,21 @@ export class CreateAccount extends SwankyCommand { } this.swankyConfig.accounts.push(accountData); - if(this.swankyConfig.defaultAccount === null) { + if (this.swankyConfig.defaultAccount === null) { this.swankyConfig.defaultAccount = accountData.alias; } - if(flags.global) { - await this.storeSystemConfig(); - } - else if(isLocalConfigCheck()) { - await this.storeConfig(process.cwd()); - } else { - throw new Error("Cannot store account to config. Please run this command in a swanky project directory"); + try { + if (isLocalConfigCheck()) { + await this.storeConfig(process.cwd()); + if (flags.global) { + await this.storeSystemConfig(); + } + } else { + await this.storeSystemConfig(); + } + } catch (cause) { + throw new FileError("Error storing created account in config", { cause }); } this.log( diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 27d90cb1..535e18f1 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -3,7 +3,7 @@ import chalk from "chalk"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; -import { ConfigError } from "../../lib/errors.js"; +import { ConfigError, FileError } from "../../lib/errors.js"; import { isLocalConfigCheck } from "../../lib/index.js"; export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; @@ -11,7 +11,7 @@ export class DefaultAccount extends SwankyCommand { static flags = { global: Flags.boolean({ char: "g", - description: "Set default account globally", + description: "Set default account globally: stored in both Swanky system and local configs.", }), } @@ -52,13 +52,17 @@ export class DefaultAccount extends SwankyCommand { }); } - if(flags.global) { - await this.storeSystemConfig(); - } - else if(isLocalConfigCheck()) { - await this.storeConfig(process.cwd()); - } else { - throw new Error("Cannot store account to config. Please run this command in a swanky project directory"); + try { + if (isLocalConfigCheck()) { + await this.storeConfig(process.cwd()); + if (flags.global) { + await this.storeSystemConfig(); + } + } else { + await this.storeSystemConfig(); + } + } catch (cause) { + throw new FileError("Error storing created account in config", { cause }); } console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); From 6007e316955ebfd19120d62d154978d6967d8624 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 25 Jan 2024 18:11:55 +0100 Subject: [PATCH 08/33] fix: isLocalConfigCheck fixed --- src/lib/command-utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index 30388e7d..037871a3 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -171,7 +171,7 @@ export function buildSwankyConfig() { }; } -export function isLocalConfigCheck() { - console.log("process.env.SWANKY_CONFIG", process.env.SWANKY_CONFIG); - return process.env.SWANKY_CONFIG != "" || existsSync(process.cwd() + "/swanky.config.json"); +export function isLocalConfigCheck(): boolean { + const defaultLocalPath = process.cwd() + "/swanky.config.json"; + return Boolean(process.env.SWANKY_CONFIG) ?? existsSync(defaultLocalPath); } \ No newline at end of file From 39bf8facc8fb94be7407bfac8bced9f454f5386f Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 25 Jan 2024 18:14:46 +0100 Subject: [PATCH 09/33] fix: Allow some commands to be used without local config --- src/commands/account/create.ts | 5 +++++ src/commands/account/default.ts | 5 +++++ src/commands/account/list.ts | 5 +++++ src/commands/check/index.ts | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 518fc2e6..2097ffbf 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -20,6 +20,11 @@ export class CreateAccount extends SwankyCommand { }), }; + constructor(argv: string[], baseConfig: any) { + super(argv, baseConfig); + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false; + } + async run(): Promise { const { flags } = await this.parse(CreateAccount); diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 535e18f1..3a3ebe24 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -23,6 +23,11 @@ export class DefaultAccount extends SwankyCommand { }), }; + constructor(argv: string[], baseConfig: any) { + super(argv, baseConfig); + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false; + } + async run(): Promise { const { args, flags } = await this.parse(DefaultAccount); diff --git a/src/commands/account/list.ts b/src/commands/account/list.ts index 08bfb4c6..67f05ecd 100644 --- a/src/commands/account/list.ts +++ b/src/commands/account/list.ts @@ -5,6 +5,11 @@ export class ListAccounts extends SwankyCommand { static description = "List dev accounts stored in config"; static aliases = [`account:ls`]; + constructor(argv: string[], baseConfig: any) { + super(argv, baseConfig); + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false; + } + async run(): Promise { const countOfDevAccounts = this.swankyConfig.accounts.filter((account) => account.isDev).length; diff --git a/src/commands/check/index.ts b/src/commands/check/index.ts index 2304f8ad..f3091b25 100644 --- a/src/commands/check/index.ts +++ b/src/commands/check/index.ts @@ -27,6 +27,11 @@ interface Ctx { export default class Check extends SwankyCommand { static description = "Check installed package versions and compatibility"; + constructor(argv: string[], baseConfig: any) { + super(argv, baseConfig); + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false; + } + public async run(): Promise { const tasks = new Listr([ { From 5cff10e94d6cedd7fc2b7b523272869ec48cfa00 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 25 Jan 2024 18:15:53 +0100 Subject: [PATCH 10/33] fix: Wait for config store async functions --- src/commands/init/index.ts | 7 ++++--- src/commands/node/install.ts | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index b1d0eb22..f6742da0 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -153,12 +153,13 @@ export class Init extends SwankyCommand { }); this.taskQueue.push({ - task: () => { - this.storeConfig(this.projectPath); - this.storeSystemConfig(); + task: async () => { + await this.storeConfig(this.projectPath); + await this.storeSystemConfig(); }, args: [], runningMessage: "Writing config", + shouldExitOnError: true }); for (const { diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 36eac4b9..dbaddfd4 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -35,8 +35,7 @@ export class InstallNode extends SwankyCommand { }; await this.spinner.runCommand( - () => - this.storeConfig(projectPath), + async () => await this.storeConfig(projectPath), "Updating swanky config" ); From b8b947f6b7e9a8ea3be48c862548f1b9af87f109 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Fri, 26 Jan 2024 08:30:50 +0100 Subject: [PATCH 11/33] fix: isLocalConfigCheck fixed --- src/lib/command-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index 037871a3..0f91661b 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -173,5 +173,5 @@ export function buildSwankyConfig() { export function isLocalConfigCheck(): boolean { const defaultLocalPath = process.cwd() + "/swanky.config.json"; - return Boolean(process.env.SWANKY_CONFIG) ?? existsSync(defaultLocalPath); + return Boolean(process.env.SWANKY_CONFIG) || existsSync(defaultLocalPath); } \ No newline at end of file From e4fffc7d03ad8657e7442d851f4159fb74015972 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 13:13:41 +0200 Subject: [PATCH 12/33] fix: Make config name dynamic --- src/commands/account/default.ts | 4 ++-- src/commands/contract/compile.ts | 4 ++-- src/commands/contract/deploy.ts | 14 +++++++++++--- src/commands/contract/explain.ts | 3 ++- src/commands/contract/test.ts | 3 ++- src/commands/contract/typegen.ts | 2 +- src/lib/command-utils.ts | 14 ++++++++++++-- src/lib/contractCall.ts | 16 ++++++++++++---- src/lib/swankyCommand.ts | 4 ++-- 9 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 3a3ebe24..75ec58f4 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -4,7 +4,7 @@ import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError, FileError } from "../../lib/errors.js"; -import { isLocalConfigCheck } from "../../lib/index.js"; +import { isLocalConfigCheck, configName } from "../../lib/index.js"; export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; @@ -36,7 +36,7 @@ export class DefaultAccount extends SwankyCommand { (account: AccountData) => account.alias === args.accountAlias ); if (!accountData) { - throw new ConfigError("Provided account alias not found in swanky.config.json"); + throw new ConfigError(`Provided account alias not found in "${configName()}"`); } this.swankyConfig.defaultAccount = accountData.alias; } else { diff --git a/src/commands/contract/compile.ts b/src/commands/contract/compile.ts index a42ccddf..aa14bd27 100644 --- a/src/commands/contract/compile.ts +++ b/src/commands/contract/compile.ts @@ -1,6 +1,6 @@ import { Args, Flags } from "@oclif/core"; import path from "node:path"; -import { storeArtifacts, Spinner, generateTypes } from "../../lib/index.js"; +import { storeArtifacts, Spinner, generateTypes, configName } from "../../lib/index.js"; import { spawn } from "node:child_process"; import { pathExists } from "fs-extra/esm"; import { SwankyCommand } from "../../lib/swankyCommand.js"; @@ -49,7 +49,7 @@ export class CompileContract extends SwankyCommand { const contractInfo = this.swankyConfig.contracts[contractName]; if (!contractInfo) { throw new ConfigError( - `Cannot find contract info for ${contractName} contract in swanky.config.json` + `Cannot find contract info for ${contractName} contract in "${configName()}"` ); } const contractPath = path.resolve("contracts", contractInfo.name); diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 84350e0c..66685145 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -1,6 +1,14 @@ import { Args, Flags } from "@oclif/core"; import { cryptoWaitReady } from "@polkadot/util-crypto/crypto"; -import { resolveNetworkUrl, ChainApi, ChainAccount, decrypt, AbiType, ensureAccountIsSet } from "../../lib/index.js"; +import { + resolveNetworkUrl, + ChainApi, + ChainAccount, + decrypt, + AbiType, + ensureAccountIsSet, + configName, +} from "../../lib/index.js"; import { AccountData, Encrypted } from "../../types/index.js"; import inquirer from "inquirer"; import chalk from "chalk"; @@ -52,7 +60,7 @@ export class DeployContract extends SwankyCommand { const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in swanky.config.json` + `Cannot find a contract named ${args.contractName} in "${configName()}"` ); } @@ -80,7 +88,7 @@ export class DeployContract extends SwankyCommand { (account: AccountData) => account.alias === accountAlias ); if (!accountData) { - throw new ConfigError("Provided account alias not found in swanky.config.json"); + throw new ConfigError(`Provided account alias not found in "${configName()}"`); } if (accountData.isDev && flags.network !== "local") { diff --git a/src/commands/contract/explain.ts b/src/commands/contract/explain.ts index b171338d..3efba84e 100644 --- a/src/commands/contract/explain.ts +++ b/src/commands/contract/explain.ts @@ -2,6 +2,7 @@ import { SwankyCommand } from "../../lib/swankyCommand.js"; import { Args } from "@oclif/core"; import { Contract } from "../../lib/contract.js"; import { ConfigError, FileError } from "../../lib/errors.js"; +import { configName } from "../../lib/index.js"; export class ExplainContract extends SwankyCommand { static description = "Explain contract messages based on the contracts' metadata"; @@ -20,7 +21,7 @@ export class ExplainContract extends SwankyCommand { const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in swanky.config.json` + `Cannot find a contract named ${args.contractName} in "${configName()}"` ); } diff --git a/src/commands/contract/test.ts b/src/commands/contract/test.ts index 216eb6b0..dbb0e455 100644 --- a/src/commands/contract/test.ts +++ b/src/commands/contract/test.ts @@ -8,6 +8,7 @@ import shell from "shelljs"; import { Contract } from "../../lib/contract.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError, FileError, InputError, TestError } from "../../lib/errors.js"; +import { configName } from "../../lib/index.js"; declare global { var contractTypesPath: string; // eslint-disable-line no-var @@ -49,7 +50,7 @@ export class TestContract extends SwankyCommand { const contractRecord = this.swankyConfig.contracts[contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in swanky.config.json` + `Cannot find a contract named ${args.contractName} in "${configName()}"` ); } diff --git a/src/commands/contract/typegen.ts b/src/commands/contract/typegen.ts index 391e0a3c..5a1e4cc6 100644 --- a/src/commands/contract/typegen.ts +++ b/src/commands/contract/typegen.ts @@ -21,7 +21,7 @@ export class TypegenCommand extends SwankyCommand { const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in swanky.config.json` + `Cannot find a contract named ${args.contractName} in "${configName()}"` ); } diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index 037871a3..aaf8257c 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -29,7 +29,7 @@ export async function getSwankyConfig(): Promise { const config = await readJSON(configPath); return config; } catch (cause) { - throw new InputError("Error reading swanky.config.json in the current directory!", { cause }); + throw new InputError(`Error reading "${configName()}" in the current directory!`, { cause }); } } @@ -173,5 +173,15 @@ export function buildSwankyConfig() { export function isLocalConfigCheck(): boolean { const defaultLocalPath = process.cwd() + "/swanky.config.json"; - return Boolean(process.env.SWANKY_CONFIG) ?? existsSync(defaultLocalPath); + return process.env.SWANKY_CONFIG === undefined ? existsSync(defaultLocalPath) : existsSync(process.env.SWANKY_CONFIG); +} + +export function configName() { + if(isLocalConfigCheck()) { + const configPathArray = (process.env.SWANKY_CONFIG === undefined ? + ["swanky.config.json"] : process.env.SWANKY_CONFIG.split("/")); + + return configPathArray[configPathArray.length - 1]; + } + return "swanky.config.json"; } \ No newline at end of file diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index a1d56606..4f735b11 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -1,4 +1,12 @@ -import { AbiType, ChainAccount, ChainApi, decrypt, ensureAccountIsSet, resolveNetworkUrl } from "./index.js"; +import { + AbiType, + ChainAccount, + ChainApi, + decrypt, + ensureAccountIsSet, + configName, + resolveNetworkUrl, +} from "./index.js"; import { AccountData, ContractData, DeploymentData, Encrypted } from "../types/index.js"; import { Args, Command, Flags, Interfaces } from "@oclif/core"; import inquirer from "inquirer"; @@ -44,7 +52,7 @@ export abstract class ContractCall extends SwankyComma const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in swanky.config.json` + `Cannot find a contract named ${args.contractName} in "${configName()}"` ); } @@ -72,7 +80,7 @@ export abstract class ContractCall extends SwankyComma if (!deploymentData?.address) throw new NetworkError( - `Cannot find a deployment with address: ${flags.address} in swanky.config.json` + `Cannot find a deployment with address: ${flags.address} in "${configName()}"` ); this.deploymentInfo = deploymentData; @@ -85,7 +93,7 @@ export abstract class ContractCall extends SwankyComma (account: AccountData) => account.alias === accountAlias ); if (!accountData) { - throw new ConfigError(`Provided account alias(${chalk.redBright(accountAlias)}) not found in swanky.config.json`); + throw new ConfigError(`Provided account alias(${chalk.redBright(accountAlias)}) not found in ${configName()}`); } if(accountData.isDev && (flags.network !== "local" || !flags.network)) { diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index bb0f8c3f..94ad1bfb 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -4,7 +4,7 @@ import { getSwankyConfig, Spinner, findSwankySystemConfigPath, - buildSwankyConfig, + buildSwankyConfig, configName, } from "./index.js"; import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; @@ -63,7 +63,7 @@ export abstract class SwankyCommand extends Command { } catch (error) { this.logger.warn("No local config found") if (error instanceof Error && - error.message.includes("swanky.config.json") && + error.message.includes(configName()) && (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG ) throw new ConfigError(`Cannot find ${process.env.SWANKY_CONFIG ?? "swanky.config.json"}`, { cause: error }); From fc0a000c97f5b998f6865d21d0836f87a4ea8cd7 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 13:41:52 +0200 Subject: [PATCH 13/33] fix: Make config name dynamic --- src/commands/contract/typegen.ts | 8 +++---- src/lib/contractCall.ts | 40 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/commands/contract/typegen.ts b/src/commands/contract/typegen.ts index 5a1e4cc6..ceb8ac19 100644 --- a/src/commands/contract/typegen.ts +++ b/src/commands/contract/typegen.ts @@ -1,5 +1,5 @@ import { Args } from "@oclif/core"; -import { generateTypes } from "../../lib/index.js"; +import { configName, generateTypes } from "../../lib/index.js"; import { Contract } from "../../lib/contract.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError, FileError } from "../../lib/errors.js"; @@ -21,7 +21,7 @@ export class TypegenCommand extends SwankyCommand { const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in "${configName()}"` + `Cannot find a contract named ${args.contractName} in "${configName()}"`, ); } @@ -29,7 +29,7 @@ export class TypegenCommand extends SwankyCommand { if (!(await contract.pathExists())) { throw new FileError( - `Path to contract ${args.contractName} does not exist: ${contract.contractPath}` + `Path to contract ${args.contractName} does not exist: ${contract.contractPath}`, ); } @@ -37,7 +37,7 @@ export class TypegenCommand extends SwankyCommand { if (!artifactsCheck.result) { throw new FileError( - `No artifact file found at path: ${artifactsCheck.missingPaths.toString()}` + `No artifact file found at path: ${artifactsCheck.missingPaths.toString()}`, ); } diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index 4f735b11..a49afa85 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -2,9 +2,9 @@ import { AbiType, ChainAccount, ChainApi, + configName, decrypt, ensureAccountIsSet, - configName, resolveNetworkUrl, } from "./index.js"; import { AccountData, ContractData, DeploymentData, Encrypted } from "../types/index.js"; @@ -52,7 +52,7 @@ export abstract class ContractCall extends SwankyComma const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( - `Cannot find a contract named ${args.contractName} in "${configName()}"` + `Cannot find a contract named ${args.contractName} in "${configName()}"`, ); } @@ -60,7 +60,7 @@ export abstract class ContractCall extends SwankyComma if (!(await contract.pathExists())) { throw new FileError( - `Path to contract ${args.contractName} does not exist: ${contract.contractPath}` + `Path to contract ${args.contractName} does not exist: ${contract.contractPath}`, ); } @@ -68,19 +68,19 @@ export abstract class ContractCall extends SwankyComma if (!artifactsCheck.result) { throw new FileError( - `No artifact file found at path: ${artifactsCheck.missingPaths.toString()}` + `No artifact file found at path: ${artifactsCheck.missingPaths.toString()}`, ); } const deploymentData = flags.address ? contract.deployments.find( - (deployment: DeploymentData) => deployment.address === flags.address - ) + (deployment: DeploymentData) => deployment.address === flags.address, + ) : contract.deployments[0]; if (!deploymentData?.address) throw new NetworkError( - `Cannot find a deployment with address: ${flags.address} in "${configName()}"` + `Cannot find a deployment with address: ${flags.address} in "${configName()}"`, ); this.deploymentInfo = deploymentData; @@ -90,13 +90,13 @@ export abstract class ContractCall extends SwankyComma const accountAlias = flags.account ?? this.swankyConfig.defaultAccount; const accountData = this.swankyConfig.accounts.find( - (account: AccountData) => account.alias === accountAlias + (account: AccountData) => account.alias === accountAlias, ); if (!accountData) { throw new ConfigError(`Provided account alias(${chalk.redBright(accountAlias)}) not found in ${configName()}`); } - if(accountData.isDev && (flags.network !== "local" || !flags.network)) { + if (accountData.isDev && (flags.network !== "local" || !flags.network)) { throw new ConfigError(`Account ${chalk.redBright(accountAlias)} is a dev account and can only be used on the local network`); } @@ -108,17 +108,17 @@ export abstract class ContractCall extends SwankyComma const mnemonic = accountData.isDev ? (accountData.mnemonic as string) : decrypt( - accountData.mnemonic as Encrypted, - ( - await inquirer.prompt([ - { - type: "password", - message: `Enter password for ${chalk.yellowBright(accountData.alias)}: `, - name: "password", - }, - ]) - ).password - ); + accountData.mnemonic as Encrypted, + ( + await inquirer.prompt([ + { + type: "password", + message: `Enter password for ${chalk.yellowBright(accountData.alias)}: `, + name: "password", + }, + ]) + ).password, + ); const account = (await this.spinner.runCommand(async () => { await cryptoWaitReady(); From ede09f60bc1a185dc83f59de7aa02d5fb523235d Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 14:25:08 +0200 Subject: [PATCH 14/33] fix: Add alice and bob to accountsby default --- src/lib/command-utils.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index aaf8257c..dbdffa2a 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -160,7 +160,20 @@ export function buildSwankyConfig() { supportedInk: swankyNode.supportedInk, }, defaultAccount: DEFAULT_ACCOUNT, - accounts: [], + accounts: [ + { + "alias": "alice", + "mnemonic": "//Alice", + "isDev": true, + "address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" + }, + { + "alias": "bob", + "mnemonic": "//Bob", + "isDev": true, + "address": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty" + }, + ], networks: { local: { url: DEFAULT_NETWORK_URL }, astar: { url: DEFAULT_ASTAR_NETWORK_URL }, From 1c95829a31312df5214a6910b92f7b83e513f398 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 14:28:21 +0200 Subject: [PATCH 15/33] fix: Display account alias in Errors --- src/commands/account/default.ts | 2 +- src/commands/contract/deploy.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 75ec58f4..16a1c6df 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -36,7 +36,7 @@ export class DefaultAccount extends SwankyCommand { (account: AccountData) => account.alias === args.accountAlias ); if (!accountData) { - throw new ConfigError(`Provided account alias not found in "${configName()}"`); + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); } this.swankyConfig.defaultAccount = accountData.alias; } else { diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 66685145..c61c2259 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -88,7 +88,7 @@ export class DeployContract extends SwankyCommand { (account: AccountData) => account.alias === accountAlias ); if (!accountData) { - throw new ConfigError(`Provided account alias not found in "${configName()}"`); + throw new ConfigError(`Provided account alias ${chalk.yellowBright(accountAlias)} not found in "${configName()}"`); } if (accountData.isDev && flags.network !== "local") { From 7a42fd3ec719090d6ab4595e493f647bb61a2d28 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 14:28:52 +0200 Subject: [PATCH 16/33] fix: Remove useless warning --- src/lib/swankyCommand.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index 94ad1bfb..0fc74135 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -50,9 +50,7 @@ export abstract class SwankyCommand extends Command { ...this.swankyConfig, ...systemConfig, }; - } catch (error) { - this.logger.warn("No system config found") - } + } catch(e) { /* empty */ } try { const localConfig = await getSwankyConfig(); @@ -77,10 +75,7 @@ export abstract class SwankyCommand extends Command { protected async storeConfig(projectPath: string) { const configPath = process.env.SWANKY_CONFIG ?? path.resolve(projectPath, "swanky.config.json"); - const localConfig : SwankyConfig = { - ...this.swankyConfig, - } - await writeJSON(configPath, localConfig, { spaces: 2 }); + await writeJSON(configPath, this.swankyConfig, { spaces: 2 }); } protected async storeSystemConfig() { @@ -106,7 +101,6 @@ export abstract class SwankyCommand extends Command { protected async finally(_: Error | undefined): Promise { // called after run and catch regardless of whether or not the command errored - // console.log("Swanky Config: ", this.swankyConfig); return super.finally(_); } } From 30000e8c13e2ca904f645911ac2b942b37b6c938 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 15:34:24 +0200 Subject: [PATCH 17/33] fix: Change config merging --- src/lib/swankyCommand.ts | 45 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index 0fc74135..fe452b59 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -1,18 +1,20 @@ import { Command, Flags, Interfaces } from "@oclif/core"; import { - getSwankySystemConfig, + buildSwankyConfig, + configName, + findSwankySystemConfigPath, getSwankyConfig, + getSwankySystemConfig, Spinner, - findSwankySystemConfigPath, - buildSwankyConfig, configName, } from "./index.js"; import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; -import { mkdirSync, existsSync } from "fs"; +import { existsSync, mkdirSync } from "fs"; import { BaseError, ConfigError, UnknownError } from "./errors.js"; import { swankyLogger } from "./logger.js"; import { Logger } from "winston"; import path from "node:path"; + export type Flags = Interfaces.InferredFlags< (typeof SwankyCommand)["baseFlags"] & T["flags"] >; @@ -46,20 +48,28 @@ export abstract class SwankyCommand extends Command { try { const systemConfig = await getSwankySystemConfig(); - this.swankyConfig = { - ...this.swankyConfig, - ...systemConfig, - }; - } catch(e) { /* empty */ } + + Object.entries(systemConfig).forEach((entry) => { + this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; + }); + } catch (error) { + await this.storeSystemConfig(); + } try { const localConfig = await getSwankyConfig(); - this.swankyConfig = { - ...this.swankyConfig, - ...localConfig, - }; + + Object.entries(this.swankyConfig).forEach((entry) => { + if (Object.entries(localConfig[entry[0] as keyof SwankyConfig] as object).length === 0) { + localConfig[entry[0] as keyof SwankyConfig] = entry[1]; + } + }); + + Object.entries(localConfig).forEach((entry) => { + this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; + }); } catch (error) { - this.logger.warn("No local config found") + this.logger.warn("No local config found"); if (error instanceof Error && error.message.includes(configName()) && (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG @@ -79,11 +89,11 @@ export abstract class SwankyCommand extends Command { } protected async storeSystemConfig() { - const systemConfig : SwankySystemConfig = { + const systemConfig: SwankySystemConfig = { defaultAccount: this.swankyConfig.defaultAccount, accounts: this.swankyConfig.accounts, - networks: this.swankyConfig.networks - } + networks: this.swankyConfig.networks, + }; const configPath = findSwankySystemConfigPath(); @@ -92,6 +102,7 @@ export abstract class SwankyCommand extends Command { } await writeJSON(configPath + "/swanky.config.json", systemConfig, { spaces: 2 }); } + protected async catch(err: Error & { exitCode?: number }): Promise { // add any custom logic to handle errors from the command // or simply return the parent class error handling From b96ebfa00ffe1824b9d78a878087f094cf5c5d31 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 16:11:40 +0200 Subject: [PATCH 18/33] fix: Fix merging accounts created outside of project --- src/lib/swankyCommand.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index fe452b59..dccad237 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -100,6 +100,14 @@ export abstract class SwankyCommand extends Command { if (!existsSync(path.resolve(configPath))) { mkdirSync(path.resolve(configPath), { recursive: true }); } + if (existsSync(path.resolve(configPath + "/swanky.config.json"))) { + const oldSystemConfig = await getSwankySystemConfig(); + const oldAccounts = oldSystemConfig.accounts; + oldAccounts + .filter((oldAccount) => systemConfig.accounts + .filter((newAccount) => newAccount.alias === oldAccount.alias).length === 0) + .forEach((oldAccount) => systemConfig.accounts.push(oldAccount)); + } await writeJSON(configPath + "/swanky.config.json", systemConfig, { spaces: 2 }); } From bb5f10bbab2bbc0cfe1aef5e314166166d97c60b Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 16:44:57 +0200 Subject: [PATCH 19/33] fix: Fix mismatched versions displaying --- src/commands/check/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/commands/check/index.ts b/src/commands/check/index.ts index f3091b25..40a2f924 100644 --- a/src/commands/check/index.ts +++ b/src/commands/check/index.ts @@ -124,9 +124,11 @@ export default class Check extends SwankyCommand { looseDefinitionDetected: false, }); console.log(context.versions); - Object.values(context.mismatchedVersions as any).forEach((mismatch) => - console.error(`[ERROR] ${mismatch as string}`) - ); + if(context.mismatchedVersions !== undefined) { + Object.values(context.mismatchedVersions).forEach((mismatch) => + console.error(`[ERROR] ${mismatch}`) + ); + } if (context.looseDefinitionDetected) { console.log(`\n[WARNING]Some of the ink dependencies do not have a fixed version. This can lead to accidentally installing version higher than supported by the node. From ebde7ad03494d92dd299385df78684093cd2342d Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 17:06:41 +0200 Subject: [PATCH 20/33] fix: Remove useless debug output --- src/commands/contract/deploy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index c61c2259..d1687156 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -55,8 +55,6 @@ export class DeployContract extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DeployContract); - console.log("flags", flags); - const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( From ba681bc8cceefd7c772c15ba2d1b3dfe8f3fa2b4 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 17:15:13 +0200 Subject: [PATCH 21/33] fix: Fix dev account check in local network --- src/commands/contract/query.ts | 6 ++++-- src/commands/contract/tx.ts | 1 + src/lib/contractCall.ts | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/commands/contract/query.ts b/src/commands/contract/query.ts index b094103c..0442c1e5 100644 --- a/src/commands/contract/query.ts +++ b/src/commands/contract/query.ts @@ -6,13 +6,15 @@ export class Query extends ContractCall { static args = { ...ContractCall.callArgs }; + static flags = { ...ContractCall.callFlags }; + public async run(): Promise { const { flags, args } = await this.parse(Query); const contract = new ContractPromise( this.api.apiInst, this.metadata, - this.deploymentInfo.address + this.deploymentInfo.address, ); const storageDepositLimit = null; @@ -27,7 +29,7 @@ export class Query extends ContractCall { gasLimit, storageDepositLimit, }, - ...flags.params + ...flags.params, ); await this.api.apiInst.disconnect(); diff --git a/src/commands/contract/tx.ts b/src/commands/contract/tx.ts index b7153789..49d75e30 100644 --- a/src/commands/contract/tx.ts +++ b/src/commands/contract/tx.ts @@ -17,6 +17,7 @@ export class Tx extends ContractCall { char: "a", description: "Account to sign the transaction with", }), + ...ContractCall.callFlags, }; static args = { ...ContractCall.callArgs }; diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index a49afa85..85490761 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -36,6 +36,14 @@ export abstract class ContractCall extends SwankyComma }), }; + static callFlags = { + network: Flags.string({ + char: "n", + default: "local", + description: "Name of network to connect to", + }), + } + protected flags!: JoinedFlagsType; protected args!: Record; protected contractInfo!: ContractData; @@ -48,6 +56,7 @@ export abstract class ContractCall extends SwankyComma await super.init(); const { flags, args } = await this.parse(this.ctor); this.args = args; + this.flags = flags as JoinedFlagsType; const contractRecord = this.swankyConfig.contracts[args.contractName]; if (!contractRecord) { From 15a0330ee3d822790ac3d4a47a265bd516a26314 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 26 Jan 2024 17:26:04 +0200 Subject: [PATCH 22/33] fix: Add check for node binary existence --- src/commands/node/start.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/commands/node/start.ts b/src/commands/node/start.ts index cb976870..e26e3a07 100644 --- a/src/commands/node/start.ts +++ b/src/commands/node/start.ts @@ -28,6 +28,9 @@ export class StartNode extends SwankyCommand { async run(): Promise { const { flags } = await this.parse(StartNode); + if(this.swankyConfig.node.localPath === "") { + this.error("Swanky node is not installed. Please run `swanky node:install` first."); + } // Run persistent mode by default. non-persistent mode in case flag is provided. // Non-Persistent mode (`--dev`) allows all CORS origin, without `--dev`, users need to specify origins by `--rpc-cors`. await execaCommand( From 1ab38ddce1810a3ec6c48974ab04e5f2b870f4d9 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Tue, 30 Jan 2024 12:37:17 +0100 Subject: [PATCH 23/33] fix: Correct account alias used for deploy and tx commands --- src/commands/contract/deploy.ts | 6 ++---- src/commands/contract/tx.ts | 5 ----- src/lib/contractCall.ts | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index d1687156..c807ef94 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -15,15 +15,13 @@ import chalk from "chalk"; import { Contract } from "../../lib/contract.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ApiError, ConfigError, FileError } from "../../lib/errors.js"; -import { DEFAULT_ACCOUNT } from "../../lib/consts.js"; export class DeployContract extends SwankyCommand { static description = "Deploy contract to a running node"; static flags = { account: Flags.string({ - default: DEFAULT_ACCOUNT, - description: "Alias of account to be used", + description: "Account alias to deploy contract with", }), gas: Flags.integer({ char: "g", @@ -158,7 +156,7 @@ export class DeployContract extends SwankyCommand { timestamp: Date.now(), address: contractAddress, networkUrl, - deployerAlias: flags.account, + deployerAlias: accountAlias!, }, ]; diff --git a/src/commands/contract/tx.ts b/src/commands/contract/tx.ts index 49d75e30..dbe13ce0 100644 --- a/src/commands/contract/tx.ts +++ b/src/commands/contract/tx.ts @@ -12,11 +12,6 @@ export class Tx extends ContractCall { char: "d", description: "Do a dry run, without signing the transaction", }), - account: Flags.string({ - required: true, - char: "a", - description: "Account to sign the transaction with", - }), ...ContractCall.callFlags, }; diff --git a/src/lib/contractCall.ts b/src/lib/contractCall.ts index 85490761..9bb8adaa 100644 --- a/src/lib/contractCall.ts +++ b/src/lib/contractCall.ts @@ -174,7 +174,7 @@ ContractCall.baseFlags = { }), account: Flags.string({ char: "a", - description: "Account to sign the transaction with", + description: "Account alias to sign the transaction with", }), address: Flags.string({ required: false, From 9a25dd821c6492816eed703c9a0f143763d8226d Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Tue, 30 Jan 2024 18:34:24 +0200 Subject: [PATCH 24/33] fix: Fix default command --- src/commands/account/default.ts | 104 +++++++++++++++++++++++--------- src/commands/init/index.ts | 35 ++++++----- src/lib/swankyCommand.ts | 6 +- 3 files changed, 97 insertions(+), 48 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 16a1c6df..81c4630f 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -3,8 +3,9 @@ import chalk from "chalk"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; -import { ConfigError, FileError } from "../../lib/errors.js"; -import { isLocalConfigCheck, configName } from "../../lib/index.js"; +import { ConfigError } from "../../lib/errors.js"; +import { configName, getSwankySystemConfig, isLocalConfigCheck } from "../../lib/index.js"; + export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; @@ -13,7 +14,7 @@ export class DefaultAccount extends SwankyCommand { char: "g", description: "Set default account globally: stored in both Swanky system and local configs.", }), - } + }; static args = { accountAlias: Args.string({ @@ -31,45 +32,88 @@ export class DefaultAccount extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DefaultAccount); - if(args.accountAlias) { + console.log(this.swankyConfig.accounts); + + const systemConfig = await getSwankySystemConfig(); + + if (args.accountAlias) { const accountData = this.swankyConfig.accounts.find( - (account: AccountData) => account.alias === args.accountAlias + (account: AccountData) => account.alias === args.accountAlias, + ); + const systemAccountData = systemConfig.accounts.find( + (account: AccountData) => account.alias === args.accountAlias, ); - if (!accountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); + if (isLocalConfigCheck()) { + if (!accountData) { + if (!systemAccountData) { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); + } + systemConfig.defaultAccount = systemAccountData.alias; + await this.storeSystemConfig(systemConfig); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); + } else { + this.swankyConfig.defaultAccount = accountData.alias; + await this.storeConfig(process.cwd()); + if (flags.global) { + if (!systemAccountData) { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); + } + systemConfig.defaultAccount = accountData.alias; + await this.storeSystemConfig(systemConfig); + } + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); + } + } else { + if (!accountData) { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); + } + this.swankyConfig.defaultAccount = accountData.alias; + await this.storeSystemConfig(); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)} in system config`)); } - this.swankyConfig.defaultAccount = accountData.alias; } else { + const choices = this.swankyConfig.accounts.map((account: AccountData) => { + return { + name: `${account.alias} (${account.address})`, + value: { alias: account.alias, systemConfig: false }, + }; + }); + systemConfig.accounts.forEach((account: AccountData) => { + if (!choices.find((choice: any) => choice.value.alias === account.alias)) { + choices.push({ + name: `${account.alias} (${account.address}) [system config]`, + value: { alias: account.alias, systemConfig: true }, + }); + } + }); await inquirer.prompt([ { type: "list", name: "defaultAccount", message: "Select default account", - choices: this.swankyConfig.accounts.map((account: AccountData) => { - return { - name: `${account.alias} (${account.address})`, - value: account.alias, - }; - }), + choices: choices, }, ]).then((answers) => { - this.swankyConfig.defaultAccount = answers.defaultAccount; - }); - } - - try { - if (isLocalConfigCheck()) { - await this.storeConfig(process.cwd()); - if (flags.global) { - await this.storeSystemConfig(); + if (answers.defaultAccount.systemConfig) { + systemConfig.defaultAccount = answers.defaultAccount.alias; + this.storeSystemConfig(systemConfig); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); + } else { + this.swankyConfig.defaultAccount = answers.defaultAccount.alias; + this.storeConfig(process.cwd()); + if (flags.global) { + const systemAccountData = systemConfig.accounts.find( + (account: AccountData) => account.alias === answers.defaultAccount.alias, + ); + if (!systemAccountData) { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(answers.defaultAccount.alias)} not found in system config`); + } + systemConfig.defaultAccount = answers.defaultAccount.alias; + this.storeSystemConfig(systemConfig); + } + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } - } else { - await this.storeSystemConfig(); - } - } catch (cause) { - throw new FileError("Error storing created account in config", { cause }); + }); } - - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index f6742da0..18cb0a0b 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -1,25 +1,26 @@ import { Args, Flags } from "@oclif/core"; import path from "node:path"; -import { ensureDir, writeJSON, pathExists, copy, outputFile, readJSON, remove } from "fs-extra/esm"; -import { stat, readdir, readFile } from "fs/promises"; +import { copy, ensureDir, outputFile, pathExists, readJSON, remove, writeJSON } from "fs-extra/esm"; +import { readdir, readFile, stat } from "fs/promises"; import { execaCommand, execaCommandSync } from "execa"; import { paramCase, pascalCase, snakeCase } from "change-case"; import inquirer from "inquirer"; import TOML from "@iarna/toml"; import { choice, email, name, pickTemplate } from "../../lib/prompts.js"; import { + buildSwankyConfig, checkCliDependencies, copyCommonTemplateFiles, copyContractTemplateFiles, downloadNode, + getTemplates, installDeps, processTemplates, swankyNode, - getTemplates, } from "../../lib/index.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { InputError, UnknownError } from "../../lib/errors.js"; -import { GlobEntry, globby } from "globby"; +import { globby, GlobEntry } from "globby"; import { merge } from "lodash-es"; import inquirerFuzzyPath from "inquirer-fuzzy-path"; import chalk from "chalk"; @@ -83,6 +84,7 @@ export class Init extends SwankyCommand { super(argv, config); (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false; } + projectPath = ""; taskQueue: Task[] = []; @@ -154,12 +156,15 @@ export class Init extends SwankyCommand { this.taskQueue.push({ task: async () => { - await this.storeConfig(this.projectPath); await this.storeSystemConfig(); + const defaultConfig = buildSwankyConfig(); + this.swankyConfig.accounts = defaultConfig.accounts; + this.swankyConfig.defaultAccount = defaultConfig.defaultAccount; + await this.storeConfig(this.projectPath); }, args: [], runningMessage: "Writing config", - shouldExitOnError: true + shouldExitOnError: true, }); for (const { @@ -176,7 +181,7 @@ export class Init extends SwankyCommand { runningMessage, successMessage, failMessage, - shouldExitOnError + shouldExitOnError, ); if (result && callback) { callback(result as string); @@ -268,7 +273,7 @@ export class Init extends SwankyCommand { } catch (cause) { throw new InputError( `Error reading target directory [${chalk.yellowBright(pathToExistingProject)}]`, - { cause } + { cause }, ); } @@ -288,7 +293,7 @@ export class Init extends SwankyCommand { const candidatesList: CopyCandidates = await getCopyCandidatesList( pathToExistingProject, - copyGlobsList + copyGlobsList, ); const testDir = await detectTests(pathToExistingProject); @@ -456,10 +461,10 @@ async function confirmCopyList(candidatesList: CopyCandidates) { ( item: PathEntry & { group: "contracts" | "crates" | "tests"; - } + }, ) => { resultingList[item.group]?.push(item); - } + }, ); return resultingList; } @@ -486,7 +491,7 @@ async function detectTests(pathToExistingProject: string): Promise { const { selectedDirectory } = await inquirer.prompt([ { @@ -557,7 +562,7 @@ async function getCopyCandidatesList( pathsToCopy: { contractsDirectories: string[]; cratesDirectories: string[]; - } + }, ) { const detectedPaths = { contracts: await getDirsAndFiles(projectPath, pathsToCopy.contractsDirectories), @@ -578,7 +583,7 @@ async function getGlobPaths(projectPath: string, globList: string[], isDirOnly: onlyDirectories: isDirOnly, deep: 1, objectMode: true, - } + }, ); } diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index dccad237..f31f2330 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -88,12 +88,12 @@ export abstract class SwankyCommand extends Command { await writeJSON(configPath, this.swankyConfig, { spaces: 2 }); } - protected async storeSystemConfig() { - const systemConfig: SwankySystemConfig = { + protected async storeSystemConfig(config?: SwankySystemConfig) { + const systemConfig: SwankySystemConfig = !config ? { defaultAccount: this.swankyConfig.defaultAccount, accounts: this.swankyConfig.accounts, networks: this.swankyConfig.networks, - }; + } : config; const configPath = findSwankySystemConfigPath(); From f9a604cb9fab003a6c24d344648233e663ec3798 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Tue, 30 Jan 2024 19:57:11 +0200 Subject: [PATCH 25/33] fix: Correct work when env SWANKY_CONFIG variable is set --- src/commands/account/default.ts | 36 ++++++++++++++++++--------------- src/lib/command-utils.ts | 12 +++++++++-- src/lib/swankyCommand.ts | 6 ------ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 81c4630f..713721e8 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -4,7 +4,7 @@ import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError } from "../../lib/errors.js"; -import { configName, getSwankySystemConfig, isLocalConfigCheck } from "../../lib/index.js"; +import { configName, getSwankySystemConfig, isEnvConfigCheck, isLocalConfigCheck } from "../../lib/index.js"; export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; @@ -32,8 +32,6 @@ export class DefaultAccount extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DefaultAccount); - console.log(this.swankyConfig.accounts); - const systemConfig = await getSwankySystemConfig(); if (args.accountAlias) { @@ -45,12 +43,16 @@ export class DefaultAccount extends SwankyCommand { ); if (isLocalConfigCheck()) { if (!accountData) { - if (!systemAccountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); + if (!isEnvConfigCheck() || flags.global) { + if (!systemAccountData) { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); + } + systemConfig.defaultAccount = systemAccountData.alias; + await this.storeSystemConfig(systemConfig); + console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); + } else { + throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); } - systemConfig.defaultAccount = systemAccountData.alias; - await this.storeSystemConfig(systemConfig); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); } else { this.swankyConfig.defaultAccount = accountData.alias; await this.storeConfig(process.cwd()); @@ -78,14 +80,16 @@ export class DefaultAccount extends SwankyCommand { value: { alias: account.alias, systemConfig: false }, }; }); - systemConfig.accounts.forEach((account: AccountData) => { - if (!choices.find((choice: any) => choice.value.alias === account.alias)) { - choices.push({ - name: `${account.alias} (${account.address}) [system config]`, - value: { alias: account.alias, systemConfig: true }, - }); - } - }); + if (!isEnvConfigCheck() || flags.global) { + systemConfig.accounts.forEach((account: AccountData) => { + if (!choices.find((choice: any) => choice.value.alias === account.alias)) { + choices.push({ + name: `${account.alias} (${account.address}) [system config]`, + value: { alias: account.alias, systemConfig: true }, + }); + } + }); + } await inquirer.prompt([ { type: "list", diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index dbdffa2a..90cde650 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -24,7 +24,7 @@ export async function commandStdoutOrNull(command: string): Promise { - const configPath = process.env.SWANKY_CONFIG ?? "swanky.config.json"; + const configPath : string = isEnvConfigCheck() ? process.env.SWANKY_CONFIG! : "swanky.config.json"; try { const config = await readJSON(configPath); return config; @@ -184,11 +184,19 @@ export function buildSwankyConfig() { }; } +export function isEnvConfigCheck(): boolean { + if (process.env.SWANKY_CONFIG === undefined) { + return false; + } else if (existsSync(process.env.SWANKY_CONFIG)) { + return true; + } else { + throw new ConfigError(`Provided config path ${process.env.SWANKY_CONFIG} does not exist`); + } +} export function isLocalConfigCheck(): boolean { const defaultLocalPath = process.cwd() + "/swanky.config.json"; return process.env.SWANKY_CONFIG === undefined ? existsSync(defaultLocalPath) : existsSync(process.env.SWANKY_CONFIG); } - export function configName() { if(isLocalConfigCheck()) { const configPathArray = (process.env.SWANKY_CONFIG === undefined ? diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index f31f2330..c5df9cb7 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -59,12 +59,6 @@ export abstract class SwankyCommand extends Command { try { const localConfig = await getSwankyConfig(); - Object.entries(this.swankyConfig).forEach((entry) => { - if (Object.entries(localConfig[entry[0] as keyof SwankyConfig] as object).length === 0) { - localConfig[entry[0] as keyof SwankyConfig] = entry[1]; - } - }); - Object.entries(localConfig).forEach((entry) => { this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; }); From 3a70313dc7ae46c1b832b80c8cb55ab5621d34ce Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Tue, 30 Jan 2024 19:15:17 +0100 Subject: [PATCH 26/33] feat: (WIP) Config builder created --- src/commands/account/create.ts | 15 ++++++--- src/lib/command-utils.ts | 2 ++ src/lib/config-builder.ts | 44 ++++++++++++++++++++++++++ src/lib/swankyCommand.ts | 58 +++++++++++++++++++++------------- 4 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 src/lib/config-builder.ts diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 2097ffbf..e5d6e983 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -5,6 +5,7 @@ import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { FileError } from "../../lib/errors.js"; +import { ConfigBuilder } from "../../lib/config-builder.js"; export class CreateAccount extends SwankyCommand { static description = "Create a new dev account in config"; @@ -84,19 +85,23 @@ export class CreateAccount extends SwankyCommand { accountData.mnemonic = tmpMnemonic; } - this.swankyConfig.accounts.push(accountData); + const configBuilder = new ConfigBuilder(this.swankyConfig); + configBuilder.addAccount(accountData); + if (this.swankyConfig.defaultAccount === null) { - this.swankyConfig.defaultAccount = accountData.alias; + configBuilder.setDefaultAccount(accountData.alias); } + const updatedConfig = configBuilder.build(); + try { if (isLocalConfigCheck()) { - await this.storeConfig(process.cwd()); + await this.storeConfig(updatedConfig, 'local', process.cwd()); if (flags.global) { - await this.storeSystemConfig(); + await this.storeConfig(updatedConfig, 'global'); } } else { - await this.storeSystemConfig(); + await this.storeConfig(updatedConfig, 'global'); } } catch (cause) { throw new FileError("Error storing created account in config", { cause }); diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index dbdffa2a..f2d90211 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -33,8 +33,10 @@ export async function getSwankyConfig(): Promise { } } +// consider merging config getters like storeConfig export async function getSwankySystemConfig(): Promise { try { + // consider using readJSONsync instead to remove async const config = await readJSON(findSwankySystemConfigPath() + "/swanky.config.json"); return config; } catch (cause) { diff --git a/src/lib/config-builder.ts b/src/lib/config-builder.ts new file mode 100644 index 00000000..c6ab6e7c --- /dev/null +++ b/src/lib/config-builder.ts @@ -0,0 +1,44 @@ +import { AccountData, SwankyConfig, SwankySystemConfig } from "../index.js"; + +export class ConfigBuilder { + private config: T; + + constructor(existingConfig: T) { + this.config = { ...existingConfig }; + } + + setDefaultAccount(account: string): ConfigBuilder { + this.config.defaultAccount = account; + return this; + } + + addAccount(account: AccountData): ConfigBuilder { + this.config.accounts.push(account); + return this; + } + + updateNetwork(name: string, url: string): ConfigBuilder { + if (this.config.networks?.[name]) { + this.config.networks[name].url = url; + } + return this; + } + + updateNodeSettings(nodeSettings: Partial): ConfigBuilder { + if ('node' in this.config) { + this.config.node = { ...this.config.node, ...nodeSettings }; + } + return this; + } + + updateContracts(contracts: SwankyConfig['contracts']): ConfigBuilder { + if ('contracts' in this.config) { + this.config.contracts = { ...contracts }; + } + return this; + } + + build(): T { + return this.config; + } +} diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index f31f2330..4fbf7f19 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -83,32 +83,46 @@ export abstract class SwankyCommand extends Command { Full command: ${JSON.stringify(process.argv)}`); } - protected async storeConfig(projectPath: string) { - const configPath = process.env.SWANKY_CONFIG ?? path.resolve(projectPath, "swanky.config.json"); - await writeJSON(configPath, this.swankyConfig, { spaces: 2 }); - } - - protected async storeSystemConfig(config?: SwankySystemConfig) { - const systemConfig: SwankySystemConfig = !config ? { - defaultAccount: this.swankyConfig.defaultAccount, - accounts: this.swankyConfig.accounts, - networks: this.swankyConfig.networks, - } : config; + protected async storeConfig( + config: SwankyConfig | SwankySystemConfig, + configType: "local" | "global", + projectPath?: string + ) { + let configPath: string; + + if (configType === "local") { + configPath = + process.env.SWANKY_CONFIG ?? path.resolve(projectPath ?? ".", "swanky.config.json"); + } else { + // global + configPath = findSwankySystemConfigPath() + "/swanky.config.json"; + if ("node" in config) { + // If it's a SwankyConfig, extract only the system relevant parts for the global SwankySystemConfig config + config = { + defaultAccount: config.defaultAccount, + accounts: config.accounts, + networks: config.networks, + }; + } + this.mergeWithExistingSystemConfig(config, configPath); + } - const configPath = findSwankySystemConfigPath(); + this.ensureDirectoryExists(configPath); + await writeJSON(configPath, config, { spaces: 2 }); + } - if (!existsSync(path.resolve(configPath))) { - mkdirSync(path.resolve(configPath), { recursive: true }); + private ensureDirectoryExists(filePath: string) { + const directory = path.dirname(filePath); + if (!existsSync(directory)) { + mkdirSync(directory, { recursive: true }); } - if (existsSync(path.resolve(configPath + "/swanky.config.json"))) { - const oldSystemConfig = await getSwankySystemConfig(); - const oldAccounts = oldSystemConfig.accounts; - oldAccounts - .filter((oldAccount) => systemConfig.accounts - .filter((newAccount) => newAccount.alias === oldAccount.alias).length === 0) - .forEach((oldAccount) => systemConfig.accounts.push(oldAccount)); + } + + private async mergeWithExistingSystemConfig(newConfig: SwankySystemConfig, configPath: string) { + if (existsSync(configPath)) { + const oldConfig = await getSwankySystemConfig(); + newConfig.accounts = [...new Set([...oldConfig.accounts, ...newConfig.accounts])]; } - await writeJSON(configPath + "/swanky.config.json", systemConfig, { spaces: 2 }); } protected async catch(err: Error & { exitCode?: number }): Promise { From fe99bb15d681737d243dd5b394b22bea7bd53853 Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Wed, 31 Jan 2024 16:36:32 +0200 Subject: [PATCH 27/33] fix: Correct use of new store config func --- src/commands/account/default.ts | 14 +++++++------- src/commands/contract/deploy.ts | 4 ++-- src/commands/contract/new.ts | 2 +- src/commands/init/index.ts | 4 ++-- src/commands/node/install.ts | 2 +- src/lib/swankyCommand.ts | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 713721e8..8947f05f 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -48,20 +48,20 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); } systemConfig.defaultAccount = systemAccountData.alias; - await this.storeSystemConfig(systemConfig); + await this.storeConfig(systemConfig, 'global'); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); } else { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); } } else { this.swankyConfig.defaultAccount = accountData.alias; - await this.storeConfig(process.cwd()); + await this.storeConfig(this.swankyConfig, 'local'); if (flags.global) { if (!systemAccountData) { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); } systemConfig.defaultAccount = accountData.alias; - await this.storeSystemConfig(systemConfig); + await this.storeConfig(systemConfig, 'global'); } console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } @@ -70,7 +70,7 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); } this.swankyConfig.defaultAccount = accountData.alias; - await this.storeSystemConfig(); + await this.storeConfig(this.swankyConfig, 'global'); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)} in system config`)); } } else { @@ -100,11 +100,11 @@ export class DefaultAccount extends SwankyCommand { ]).then((answers) => { if (answers.defaultAccount.systemConfig) { systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeSystemConfig(systemConfig); + this.storeConfig(systemConfig, 'global'); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); } else { this.swankyConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(process.cwd()); + this.storeConfig(this.swankyConfig, 'local'); if (flags.global) { const systemAccountData = systemConfig.accounts.find( (account: AccountData) => account.alias === answers.defaultAccount.alias, @@ -113,7 +113,7 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(answers.defaultAccount.alias)} not found in system config`); } systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeSystemConfig(systemConfig); + this.storeConfig(systemConfig, 'global'); } console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index c807ef94..0edbbf72 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -96,7 +96,7 @@ export class DeployContract extends SwankyCommand { if(this.swankyConfig.defaultAccount === null) { this.swankyConfig.defaultAccount = accountAlias; - await this.storeSystemConfig(); + await this.storeConfig(this.swankyConfig, 'local'); } const mnemonic = accountData.isDev @@ -160,7 +160,7 @@ export class DeployContract extends SwankyCommand { }, ]; - await this.storeConfig(process.cwd()); + await this.storeConfig(this.swankyConfig, 'local'); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index f8b767fa..fc65d9fa 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -102,7 +102,7 @@ export class NewContract extends SwankyCommand { deployments: [], }; - await this.storeConfig(process.cwd())}, "Writing config"); + await this.storeConfig(this.swankyConfig, 'local')}, "Writing config"); this.log("😎 New contract successfully generated! 😎"); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index 18cb0a0b..e06cad42 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -156,11 +156,11 @@ export class Init extends SwankyCommand { this.taskQueue.push({ task: async () => { - await this.storeSystemConfig(); + await this.storeConfig(this.swankyConfig, 'global'); const defaultConfig = buildSwankyConfig(); this.swankyConfig.accounts = defaultConfig.accounts; this.swankyConfig.defaultAccount = defaultConfig.defaultAccount; - await this.storeConfig(this.projectPath); + await this.storeConfig(this.swankyConfig, 'local'); }, args: [], runningMessage: "Writing config", diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index dbaddfd4..3a8b893b 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -35,7 +35,7 @@ export class InstallNode extends SwankyCommand { }; await this.spinner.runCommand( - async () => await this.storeConfig(projectPath), + async () => await this.storeConfig(this.swankyConfig, 'local'), "Updating swanky config" ); diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index a21b9f5e..7ce2d09f 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -53,7 +53,7 @@ export abstract class SwankyCommand extends Command { this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; }); } catch (error) { - await this.storeSystemConfig(); + await this.storeConfig(this.swankyConfig, 'global'); } try { From 93d41d609683e59193b82c27c8d51a900019cb9f Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Wed, 31 Jan 2024 19:41:58 +0200 Subject: [PATCH 28/33] fix: Use ConfigBuilder to change SwankyConfig --- src/commands/account/default.ts | 36 +++++++++++++++++++-------------- src/commands/contract/new.ts | 10 ++++----- src/commands/init/index.ts | 28 ++++++++++++------------- src/commands/node/install.ts | 20 ++++++++++-------- src/lib/config-builder.ts | 12 +++++++++++ src/lib/swankyCommand.ts | 12 ++++++++--- 6 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 8947f05f..4b427883 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -48,21 +48,21 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); } systemConfig.defaultAccount = systemAccountData.alias; - await this.storeConfig(systemConfig, 'global'); + await this.storeConfig(systemConfig, "global"); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); } else { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); } } else { - this.swankyConfig.defaultAccount = accountData.alias; - await this.storeConfig(this.swankyConfig, 'local'); if (flags.global) { if (!systemAccountData) { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); } systemConfig.defaultAccount = accountData.alias; - await this.storeConfig(systemConfig, 'global'); + await this.storeConfig(systemConfig, "global"); } + this.swankyConfig.defaultAccount = accountData.alias; + await this.storeConfig(this.swankyConfig, "local"); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } } else { @@ -70,16 +70,22 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); } this.swankyConfig.defaultAccount = accountData.alias; - await this.storeConfig(this.swankyConfig, 'global'); + await this.storeConfig(this.swankyConfig, "global"); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)} in system config`)); } } else { - const choices = this.swankyConfig.accounts.map((account: AccountData) => { - return { - name: `${account.alias} (${account.address})`, - value: { alias: account.alias, systemConfig: false }, - }; - }); + let choices: { + name: string, + value: { alias: string, systemConfig: boolean } + }[] = []; + if(isLocalConfigCheck()) { + this.swankyConfig.accounts.forEach((account: AccountData) => { + choices.push({ + name: `${account.alias} (${account.address})`, + value: { alias: account.alias, systemConfig: false }, + }); + }); + } if (!isEnvConfigCheck() || flags.global) { systemConfig.accounts.forEach((account: AccountData) => { if (!choices.find((choice: any) => choice.value.alias === account.alias)) { @@ -100,11 +106,9 @@ export class DefaultAccount extends SwankyCommand { ]).then((answers) => { if (answers.defaultAccount.systemConfig) { systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(systemConfig, 'global'); + this.storeConfig(systemConfig, "global"); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); } else { - this.swankyConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(this.swankyConfig, 'local'); if (flags.global) { const systemAccountData = systemConfig.accounts.find( (account: AccountData) => account.alias === answers.defaultAccount.alias, @@ -113,8 +117,10 @@ export class DefaultAccount extends SwankyCommand { throw new ConfigError(`Provided account alias ${chalk.yellowBright(answers.defaultAccount.alias)} not found in system config`); } systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(systemConfig, 'global'); + this.storeConfig(systemConfig, "global"); } + this.swankyConfig.defaultAccount = answers.defaultAccount.alias; + this.storeConfig(this.swankyConfig, "local"); console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); } }); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index fc65d9fa..9e338585 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -13,6 +13,7 @@ import { execaCommandSync } from "execa"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { InputError } from "../../lib/errors.js"; +import { ConfigBuilder } from "../../lib/config-builder.js"; export class NewContract extends SwankyCommand { static description = "Generate a new smart contract template inside a project"; @@ -96,13 +97,10 @@ export class NewContract extends SwankyCommand { await ensureDir(path.resolve(projectPath, "tests", args.contractName)); await this.spinner.runCommand(async () => { - this.swankyConfig.contracts[args.contractName] = { - name: args.contractName, - moduleName: snakeCase(args.contractName), - deployments: [], - }; + const configBuilder = new ConfigBuilder(this.swankyConfig); + configBuilder.addContract(args.contractName); - await this.storeConfig(this.swankyConfig, 'local')}, "Writing config"); + await this.storeConfig(configBuilder.build(), 'local')}, "Writing config"); this.log("😎 New contract successfully generated! 😎"); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index e06cad42..20e1c673 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -8,7 +8,6 @@ import inquirer from "inquirer"; import TOML from "@iarna/toml"; import { choice, email, name, pickTemplate } from "../../lib/prompts.js"; import { - buildSwankyConfig, checkCliDependencies, copyCommonTemplateFiles, copyContractTemplateFiles, @@ -24,6 +23,8 @@ import { globby, GlobEntry } from "globby"; import { merge } from "lodash-es"; import inquirerFuzzyPath from "inquirer-fuzzy-path"; import chalk from "chalk"; +import { ConfigBuilder } from "../../lib/config-builder.js"; +import { SwankyConfig } from "../../types/index.js"; type TaskFunction = (...args: any[]) => any; @@ -89,10 +90,13 @@ export class Init extends SwankyCommand { taskQueue: Task[] = []; + configBuilder = new ConfigBuilder({} as SwankyConfig); + async run(): Promise { const { args, flags } = await this.parse(Init); this.projectPath = path.resolve(args.projectName); + this.configBuilder = new ConfigBuilder(this.swankyConfig); // check if projectPath dir exists and is it empty try { @@ -144,7 +148,7 @@ export class Init extends SwankyCommand { args: [this.projectPath, swankyNode, this.spinner], runningMessage: "Downloading Swanky node", callback: (result) => - this.swankyConfig.node ? (this.swankyConfig.node.localPath = result) : null, + this.configBuilder.build().node ? (this.configBuilder.updateNodeSettings({ localPath: result })) : null, }); } } @@ -156,11 +160,9 @@ export class Init extends SwankyCommand { this.taskQueue.push({ task: async () => { + this.swankyConfig = this.configBuilder.build(); await this.storeConfig(this.swankyConfig, 'global'); - const defaultConfig = buildSwankyConfig(); - this.swankyConfig.accounts = defaultConfig.accounts; - this.swankyConfig.defaultAccount = defaultConfig.defaultAccount; - await this.storeConfig(this.swankyConfig, 'local'); + await this.storeConfig(this.swankyConfig, 'local', this.projectPath); }, args: [], runningMessage: "Writing config", @@ -253,13 +255,13 @@ export class Init extends SwankyCommand { runningMessage: "Processing templates", }); - this.swankyConfig.contracts = { + this.configBuilder.updateContracts( { [contractName as string]: { name: contractName, moduleName: snakeCase(contractName), deployments: [], }, - }; + }); } async convert(pathToExistingProject: string, projectName: string) { @@ -329,14 +331,12 @@ export class Init extends SwankyCommand { }, }); - if (!this.swankyConfig.contracts) this.swankyConfig.contracts = {}; + if (!this.configBuilder.build().contracts){ + this.configBuilder.updateContracts({}) + } for (const contract of confirmedCopyList.contracts) { - this.swankyConfig.contracts[contract.name] = { - name: contract.name, - moduleName: contract.moduleName!, - deployments: [], - }; + this.configBuilder.addContract(contract.name, contract.moduleName); } let rootToml = await readRootCargoToml(pathToExistingProject); diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 3a8b893b..78e4684d 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -2,6 +2,7 @@ import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ux } from "@oclif/core"; import { downloadNode, swankyNode } from "../../lib/index.js"; import path from "node:path"; +import { ConfigBuilder } from "../../lib/config-builder.js"; export class InstallNode extends SwankyCommand { static description = "Install swanky node binary"; @@ -26,16 +27,19 @@ export class InstallNode extends SwankyCommand { () => downloadNode(projectPath, swankyNode, this.spinner), "Downloading Swanky node" )) as string; - const nodePath = path.relative(projectPath, taskResult); - - this.swankyConfig.node = { - localPath: nodePath, - polkadotPalletVersions: swankyNode.polkadotPalletVersions, - supportedInk: swankyNode.supportedInk, - }; + const nodePath = path.resolve(projectPath, taskResult); await this.spinner.runCommand( - async () => await this.storeConfig(this.swankyConfig, 'local'), + async () => { + const configBuilder = new ConfigBuilder(this.swankyConfig); + configBuilder.updateNodeSettings({ + localPath: nodePath, + polkadotPalletVersions: swankyNode.polkadotPalletVersions, + supportedInk: swankyNode.supportedInk, + }) + this.swankyConfig = configBuilder.build(); + await this.storeConfig(this.swankyConfig, 'local') + }, "Updating swanky config" ); diff --git a/src/lib/config-builder.ts b/src/lib/config-builder.ts index c6ab6e7c..0e69f1ec 100644 --- a/src/lib/config-builder.ts +++ b/src/lib/config-builder.ts @@ -1,4 +1,5 @@ import { AccountData, SwankyConfig, SwankySystemConfig } from "../index.js"; +import { snakeCase } from "change-case"; export class ConfigBuilder { private config: T; @@ -38,6 +39,17 @@ export class ConfigBuilder { return this; } + addContract(name: string, moduleName?: string): ConfigBuilder { + if ('contracts' in this.config) { + this.config.contracts[name] = { + name: name, + moduleName: moduleName ?? snakeCase(name), + deployments: [] + }; + } + return this; + } + build(): T { return this.config; } diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index 7ce2d09f..2ed34aa5 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -45,7 +45,6 @@ export abstract class SwankyCommand extends Command { this.logger = swankyLogger; this.swankyConfig = buildSwankyConfig(); - try { const systemConfig = await getSwankySystemConfig(); @@ -98,7 +97,7 @@ export abstract class SwankyCommand extends Command { networks: config.networks, }; } - this.mergeWithExistingSystemConfig(config, configPath); + await this.mergeWithExistingSystemConfig(config, configPath); } this.ensureDirectoryExists(configPath); @@ -115,7 +114,14 @@ export abstract class SwankyCommand extends Command { private async mergeWithExistingSystemConfig(newConfig: SwankySystemConfig, configPath: string) { if (existsSync(configPath)) { const oldConfig = await getSwankySystemConfig(); - newConfig.accounts = [...new Set([...oldConfig.accounts, ...newConfig.accounts])]; + + newConfig.accounts.forEach((account) => { + if (!oldConfig.accounts.find((oldAccount) => oldAccount.alias === account.alias)) { + oldConfig.accounts.push(account); + } + }); + + newConfig.accounts = oldConfig.accounts; } } From 4708ab43943f5756ceaa0394b29723448531ee32 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Thu, 1 Feb 2024 18:12:18 +0100 Subject: [PATCH 29/33] fix: refactoring --- src/commands/account/create.ts | 34 ++++---- src/commands/account/default.ts | 142 +++++++++++--------------------- src/commands/contract/deploy.ts | 6 -- src/commands/contract/new.ts | 4 +- src/commands/init/index.ts | 19 ++--- src/commands/node/install.ts | 22 ++--- src/lib/command-utils.ts | 60 +++++++------- src/lib/consts.ts | 2 + src/lib/swankyCommand.ts | 105 +++++++++++++---------- 9 files changed, 172 insertions(+), 222 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index e5d6e983..24ffc387 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -1,6 +1,6 @@ import { Flags } from "@oclif/core"; import chalk from "chalk"; -import { ChainAccount, encrypt, isLocalConfigCheck } from "../../lib/index.js"; +import { ChainAccount, encrypt, getSwankyConfig, isLocalConfigCheck } from "../../lib/index.js"; import { AccountData } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; @@ -11,13 +11,17 @@ export class CreateAccount extends SwankyCommand { static flags = { global: Flags.boolean({ - description: "Create account globally: stored in both Swanky system and local configs.", - }), - generate: Flags.boolean({ char: "g", + description: "Create account globally stored in Swanky system config.", + + }), + new: Flags.boolean({ + char: "n", + description: "Generate a brand new account.", }), dev: Flags.boolean({ char: "d", + description: "Make this account a dev account for local network usage.", }), }; @@ -46,7 +50,7 @@ export class CreateAccount extends SwankyCommand { } let tmpMnemonic = ""; - if (flags.generate) { + if (flags.new) { tmpMnemonic = ChainAccount.generate(); console.log( `${ @@ -85,26 +89,22 @@ export class CreateAccount extends SwankyCommand { accountData.mnemonic = tmpMnemonic; } - const configBuilder = new ConfigBuilder(this.swankyConfig); + const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global"; + const config = configType === "global" ? getSwankyConfig("global") : this.swankyConfig; + + const configBuilder = new ConfigBuilder(config); configBuilder.addAccount(accountData); if (this.swankyConfig.defaultAccount === null) { configBuilder.setDefaultAccount(accountData.alias); } - const updatedConfig = configBuilder.build(); - try { - if (isLocalConfigCheck()) { - await this.storeConfig(updatedConfig, 'local', process.cwd()); - if (flags.global) { - await this.storeConfig(updatedConfig, 'global'); - } - } else { - await this.storeConfig(updatedConfig, 'global'); - } + await this.storeConfig(configBuilder.build(), configType); } catch (cause) { - throw new FileError("Error storing created account in config", { cause }); + throw new FileError(`Error storing created account in ${configType} config`, { + cause, + }); } this.log( diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 4b427883..98c78839 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -1,10 +1,11 @@ import { Args, Flags } from "@oclif/core"; import chalk from "chalk"; -import { AccountData } from "../../types/index.js"; +import { SwankySystemConfig } from "../../types/index.js"; import inquirer from "inquirer"; import { SwankyCommand } from "../../lib/swankyCommand.js"; -import { ConfigError } from "../../lib/errors.js"; -import { configName, getSwankySystemConfig, isEnvConfigCheck, isLocalConfigCheck } from "../../lib/index.js"; +import { ConfigError, FileError } from "../../lib/errors.js"; +import { getSwankyConfig, isLocalConfigCheck } from "../../lib/index.js"; +import { ConfigBuilder } from "../../lib/config-builder.js"; export class DefaultAccount extends SwankyCommand { static description = "Set default account to use"; @@ -12,7 +13,7 @@ export class DefaultAccount extends SwankyCommand { static flags = { global: Flags.boolean({ char: "g", - description: "Set default account globally: stored in both Swanky system and local configs.", + description: "Set default account globally in Swanky system config.", }), }; @@ -32,98 +33,51 @@ export class DefaultAccount extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DefaultAccount); - const systemConfig = await getSwankySystemConfig(); + const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global"; + const config = configType === "global" ? getSwankyConfig("global") : this.swankyConfig; - if (args.accountAlias) { - const accountData = this.swankyConfig.accounts.find( - (account: AccountData) => account.alias === args.accountAlias, - ); - const systemAccountData = systemConfig.accounts.find( - (account: AccountData) => account.alias === args.accountAlias, - ); - if (isLocalConfigCheck()) { - if (!accountData) { - if (!isEnvConfigCheck() || flags.global) { - if (!systemAccountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}" and system config`); - } - systemConfig.defaultAccount = systemAccountData.alias; - await this.storeConfig(systemConfig, "global"); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); - } else { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in "${configName()}"`); - } - } else { - if (flags.global) { - if (!systemAccountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); - } - systemConfig.defaultAccount = accountData.alias; - await this.storeConfig(systemConfig, "global"); - } - this.swankyConfig.defaultAccount = accountData.alias; - await this.storeConfig(this.swankyConfig, "local"); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); - } - } else { - if (!accountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(args.accountAlias)} not found in system config`); - } - this.swankyConfig.defaultAccount = accountData.alias; - await this.storeConfig(this.swankyConfig, "global"); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)} in system config`)); - } - } else { - let choices: { - name: string, - value: { alias: string, systemConfig: boolean } - }[] = []; - if(isLocalConfigCheck()) { - this.swankyConfig.accounts.forEach((account: AccountData) => { - choices.push({ - name: `${account.alias} (${account.address})`, - value: { alias: account.alias, systemConfig: false }, - }); - }); - } - if (!isEnvConfigCheck() || flags.global) { - systemConfig.accounts.forEach((account: AccountData) => { - if (!choices.find((choice: any) => choice.value.alias === account.alias)) { - choices.push({ - name: `${account.alias} (${account.address}) [system config]`, - value: { alias: account.alias, systemConfig: true }, - }); - } - }); - } - await inquirer.prompt([ - { - type: "list", - name: "defaultAccount", - message: "Select default account", - choices: choices, - }, - ]).then((answers) => { - if (answers.defaultAccount.systemConfig) { - systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(systemConfig, "global"); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(systemConfig.defaultAccount)} in system config`)); - } else { - if (flags.global) { - const systemAccountData = systemConfig.accounts.find( - (account: AccountData) => account.alias === answers.defaultAccount.alias, - ); - if (!systemAccountData) { - throw new ConfigError(`Provided account alias ${chalk.yellowBright(answers.defaultAccount.alias)} not found in system config`); - } - systemConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(systemConfig, "global"); - } - this.swankyConfig.defaultAccount = answers.defaultAccount.alias; - this.storeConfig(this.swankyConfig, "local"); - console.log(chalk.greenBright(`Default account set to ${chalk.yellowBright(this.swankyConfig.defaultAccount)}`)); - } + const accountAlias = args.accountAlias ?? (await this.promptForAccountAlias(config)); + this.ensureAccountExists(config, accountAlias); + + const configBuilder = new ConfigBuilder(config); + configBuilder.setDefaultAccount(accountAlias); + + try { + await this.storeConfig(configBuilder.build(), configType); + } catch (cause) { + throw new FileError(`Error storing default account in ${configType} config`, { + cause, }); } + + this.log( + `${chalk.greenBright("✔")} Account with alias ${chalk.yellowBright( + accountAlias + )} set as default in ${configType} config` + ); + } + + private async promptForAccountAlias(config: SwankySystemConfig): Promise { + const choices = config.accounts.map((account) => ({ + name: `${account.alias} (${account.address})`, + value: account.alias, + })); + + const answer = await inquirer.prompt([ + { + type: "list", + name: "defaultAccount", + message: "Select default account", + choices: choices, + }, + ]); + + return answer.defaultAccount; + } + + private ensureAccountExists(config: SwankySystemConfig, alias: string) { + const isSomeAccount = config.accounts.some((account) => account.alias === alias); + if (!isSomeAccount) + throw new ConfigError(`Provided account alias ${chalk.yellowBright(alias)} not found`); } } diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 0edbbf72..620b0d24 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -93,12 +93,6 @@ export class DeployContract extends SwankyCommand { ); } - if(this.swankyConfig.defaultAccount === null) - { - this.swankyConfig.defaultAccount = accountAlias; - await this.storeConfig(this.swankyConfig, 'local'); - } - const mnemonic = accountData.isDev ? (accountData.mnemonic as string) : decrypt( diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index 9e338585..c78d7284 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -99,8 +99,8 @@ export class NewContract extends SwankyCommand { await this.spinner.runCommand(async () => { const configBuilder = new ConfigBuilder(this.swankyConfig); configBuilder.addContract(args.contractName); - - await this.storeConfig(configBuilder.build(), 'local')}, "Writing config"); + await this.storeConfig(configBuilder.build(), "local"); + }, "Writing config"); this.log("😎 New contract successfully generated! 😎"); } diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index 20e1c673..f2f1b298 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -8,6 +8,7 @@ import inquirer from "inquirer"; import TOML from "@iarna/toml"; import { choice, email, name, pickTemplate } from "../../lib/prompts.js"; import { + buildSwankyConfig, checkCliDependencies, copyCommonTemplateFiles, copyContractTemplateFiles, @@ -24,7 +25,6 @@ import { merge } from "lodash-es"; import inquirerFuzzyPath from "inquirer-fuzzy-path"; import chalk from "chalk"; import { ConfigBuilder } from "../../lib/config-builder.js"; -import { SwankyConfig } from "../../types/index.js"; type TaskFunction = (...args: any[]) => any; @@ -90,13 +90,12 @@ export class Init extends SwankyCommand { taskQueue: Task[] = []; - configBuilder = new ConfigBuilder({} as SwankyConfig); + configBuilder = new ConfigBuilder(buildSwankyConfig()); async run(): Promise { const { args, flags } = await this.parse(Init); this.projectPath = path.resolve(args.projectName); - this.configBuilder = new ConfigBuilder(this.swankyConfig); // check if projectPath dir exists and is it empty try { @@ -147,8 +146,7 @@ export class Init extends SwankyCommand { task: downloadNode, args: [this.projectPath, swankyNode, this.spinner], runningMessage: "Downloading Swanky node", - callback: (result) => - this.configBuilder.build().node ? (this.configBuilder.updateNodeSettings({ localPath: result })) : null, + callback: (localPath) => this.configBuilder.updateNodeSettings({ localPath }), }); } } @@ -159,11 +157,8 @@ export class Init extends SwankyCommand { }); this.taskQueue.push({ - task: async () => { - this.swankyConfig = this.configBuilder.build(); - await this.storeConfig(this.swankyConfig, 'global'); - await this.storeConfig(this.swankyConfig, 'local', this.projectPath); - }, + task: async () => + await this.storeConfig(this.configBuilder.build(), "local", this.projectPath), args: [], runningMessage: "Writing config", shouldExitOnError: true, @@ -331,10 +326,6 @@ export class Init extends SwankyCommand { }, }); - if (!this.configBuilder.build().contracts){ - this.configBuilder.updateContracts({}) - } - for (const contract of confirmedCopyList.contracts) { this.configBuilder.addContract(contract.name, contract.moduleName); } diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 78e4684d..74559fd4 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -29,19 +29,15 @@ export class InstallNode extends SwankyCommand { )) as string; const nodePath = path.resolve(projectPath, taskResult); - await this.spinner.runCommand( - async () => { - const configBuilder = new ConfigBuilder(this.swankyConfig); - configBuilder.updateNodeSettings({ - localPath: nodePath, - polkadotPalletVersions: swankyNode.polkadotPalletVersions, - supportedInk: swankyNode.supportedInk, - }) - this.swankyConfig = configBuilder.build(); - await this.storeConfig(this.swankyConfig, 'local') - }, - "Updating swanky config" - ); + await this.spinner.runCommand(async () => { + const configBuilder = new ConfigBuilder(this.swankyConfig); + configBuilder.updateNodeSettings({ + localPath: nodePath, + polkadotPalletVersions: swankyNode.polkadotPalletVersions, + supportedInk: swankyNode.supportedInk, + }); + await this.storeConfig(configBuilder.build(), "local"); + }, "Updating swanky config"); this.log("Swanky Node Installed successfully"); } diff --git a/src/lib/command-utils.ts b/src/lib/command-utils.ts index d5957357..fa4ddd06 100644 --- a/src/lib/command-utils.ts +++ b/src/lib/command-utils.ts @@ -1,15 +1,19 @@ import { execaCommand } from "execa"; -import { copy, emptyDir, ensureDir, readJSON } from "fs-extra/esm"; +import { copy, emptyDir, ensureDir, readJSONSync } from "fs-extra/esm"; import path from "node:path"; import { DEFAULT_NETWORK_URL, ARTIFACTS_PATH, TYPED_CONTRACTS_PATH, DEFAULT_SHIBUYA_NETWORK_URL, - DEFAULT_SHIDEN_NETWORK_URL, DEFAULT_ASTAR_NETWORK_URL, DEFAULT_ACCOUNT, + DEFAULT_SHIDEN_NETWORK_URL, + DEFAULT_ASTAR_NETWORK_URL, + DEFAULT_ACCOUNT, + DEFAULT_CONFIG_NAME, + DEFAULT_CONFIG_FOLDER_NAME, } from "./consts.js"; import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; -import { ConfigError, FileError, InputError } from "./errors.js"; +import { ConfigError, FileError } from "./errors.js"; import { userInfo } from "os"; import { swankyNode } from "./nodeInfo.js"; import { existsSync } from "fs"; @@ -23,31 +27,23 @@ export async function commandStdoutOrNull(command: string): Promise { - const configPath : string = isEnvConfigCheck() ? process.env.SWANKY_CONFIG! : "swanky.config.json"; - try { - const config = await readJSON(configPath); - return config; - } catch (cause) { - throw new InputError(`Error reading "${configName()}" in the current directory!`, { cause }); - } -} +export function getSwankyConfig(configType: "local" | "global"): SwankyConfig | SwankySystemConfig { + let configPath: string; -// consider merging config getters like storeConfig -export async function getSwankySystemConfig(): Promise { - try { - // consider using readJSONsync instead to remove async - const config = await readJSON(findSwankySystemConfigPath() + "/swanky.config.json"); - return config; - } catch (cause) { - throw new ConfigError("Error reading swanky.config.json in system directory!", { cause }); + if (configType === "global") { + configPath = getSystemConfigDirectoryPath() + `/${DEFAULT_CONFIG_NAME}`; + } else { + configPath = isEnvConfigCheck() ? process.env.SWANKY_CONFIG! : DEFAULT_CONFIG_NAME; } + + const config = readJSONSync(configPath); + return config; } -export function findSwankySystemConfigPath(): string { + +export function getSystemConfigDirectoryPath(): string { const homeDir = userInfo().homedir; - const amountOfDirectories = process.cwd().split("/").length - homeDir.split("/").length; - const configPath = "../".repeat(amountOfDirectories)+"swanky"; + const configPath = homeDir + `/${DEFAULT_CONFIG_FOLDER_NAME}`; return configPath; } @@ -195,16 +191,18 @@ export function isEnvConfigCheck(): boolean { throw new ConfigError(`Provided config path ${process.env.SWANKY_CONFIG} does not exist`); } } + export function isLocalConfigCheck(): boolean { - const defaultLocalPath = process.cwd() + "/swanky.config.json"; - return process.env.SWANKY_CONFIG === undefined ? existsSync(defaultLocalPath) : existsSync(process.env.SWANKY_CONFIG); + const defaultLocalConfigPath = process.cwd() + `/${DEFAULT_CONFIG_NAME}`; + return process.env.SWANKY_CONFIG === undefined + ? existsSync(defaultLocalConfigPath) + : existsSync(process.env.SWANKY_CONFIG); } -export function configName() { - if(isLocalConfigCheck()) { - const configPathArray = (process.env.SWANKY_CONFIG === undefined ? - ["swanky.config.json"] : process.env.SWANKY_CONFIG.split("/")); - return configPathArray[configPathArray.length - 1]; +export function configName(): string { + if (!isLocalConfigCheck()) { + return DEFAULT_CONFIG_NAME + " [system config]"; } - return "swanky.config.json"; + + return process.env.SWANKY_CONFIG?.split("/").pop() ?? DEFAULT_CONFIG_NAME; } \ No newline at end of file diff --git a/src/lib/consts.ts b/src/lib/consts.ts index 90c48ff3..33a0c103 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -4,6 +4,8 @@ export const DEFAULT_SHIDEN_NETWORK_URL = "wss://rpc.shiden.astar.network"; export const DEFAULT_SHIBUYA_NETWORK_URL = "wss://shibuya.public.blastapi.io"; export const DEFAULT_ACCOUNT = "alice"; +export const DEFAULT_CONFIG_FOLDER_NAME = "swanky"; +export const DEFAULT_CONFIG_NAME = "swanky.config.json"; export const ARTIFACTS_PATH = "artifacts"; export const TYPED_CONTRACTS_PATH = "typedContracts"; diff --git a/src/lib/swankyCommand.ts b/src/lib/swankyCommand.ts index 2ed34aa5..1983f55f 100644 --- a/src/lib/swankyCommand.ts +++ b/src/lib/swankyCommand.ts @@ -2,18 +2,18 @@ import { Command, Flags, Interfaces } from "@oclif/core"; import { buildSwankyConfig, configName, - findSwankySystemConfigPath, + getSystemConfigDirectoryPath, getSwankyConfig, - getSwankySystemConfig, Spinner, } from "./index.js"; -import { SwankyConfig, SwankySystemConfig } from "../types/index.js"; +import { AccountData, SwankyConfig, SwankySystemConfig } from "../types/index.js"; import { writeJSON } from "fs-extra/esm"; import { existsSync, mkdirSync } from "fs"; import { BaseError, ConfigError, UnknownError } from "./errors.js"; import { swankyLogger } from "./logger.js"; import { Logger } from "winston"; import path from "node:path"; +import { DEFAULT_CONFIG_FOLDER_NAME, DEFAULT_CONFIG_NAME } from "./consts.js"; export type Flags = Interfaces.InferredFlags< (typeof SwankyCommand)["baseFlags"] & T["flags"] @@ -40,44 +40,58 @@ export abstract class SwankyCommand extends Command { args: this.ctor.args, strict: this.ctor.strict, }); + this.flags = flags as Flags; this.args = args as Args; this.logger = swankyLogger; this.swankyConfig = buildSwankyConfig(); - try { - const systemConfig = await getSwankySystemConfig(); - Object.entries(systemConfig).forEach((entry) => { - this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; - }); + await this.loadAndMergeConfig(); + + this.logger.info(`Running command: ${this.ctor.name} + Args: ${JSON.stringify(this.args)} + Flags: ${JSON.stringify(this.flags)} + Full command: ${JSON.stringify(process.argv)}`); + } + + protected async loadAndMergeConfig(): Promise { + try { + const systemConfig = getSwankyConfig("global"); + this.swankyConfig = { ...this.swankyConfig, ...systemConfig }; } catch (error) { - await this.storeConfig(this.swankyConfig, 'global'); + this.warn( + `No Swanky system config found; creating one in "/${DEFAULT_CONFIG_FOLDER_NAME}/${DEFAULT_CONFIG_NAME}}" at home directory` + ); + await this.storeConfig(this.swankyConfig, "global"); } try { - const localConfig = await getSwankyConfig(); - - Object.entries(localConfig).forEach((entry) => { - this.swankyConfig[entry[0] as keyof SwankyConfig] = entry[1]; - }); + const localConfig = getSwankyConfig("local") as SwankyConfig; + this.mergeAccountsWithExistingConfig(this.swankyConfig, localConfig); + const originalDefaultAccount = this.swankyConfig.defaultAccount; + this.swankyConfig = { ...this.swankyConfig, ...localConfig }; + this.swankyConfig.defaultAccount = localConfig.defaultAccount ?? originalDefaultAccount; } catch (error) { - this.logger.warn("No local config found"); - if (error instanceof Error && - error.message.includes(configName()) && - (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG - ) - throw new ConfigError(`Cannot find ${process.env.SWANKY_CONFIG ?? "swanky.config.json"}`, { cause: error }); + this.handleLocalConfigError(error); } + } - this.logger.info(`Running command: ${this.ctor.name} - Args: ${JSON.stringify(this.args)} - Flags: ${JSON.stringify(this.flags)} - Full command: ${JSON.stringify(process.argv)}`); + private handleLocalConfigError(error: unknown): void { + this.logger.warn("No local config found"); + if ( + error instanceof Error && + error.message.includes(configName()) && + (this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG + ) { + throw new ConfigError(`Cannot find ${process.env.SWANKY_CONFIG ?? DEFAULT_CONFIG_NAME}`, { + cause: error, + }); + } } protected async storeConfig( - config: SwankyConfig | SwankySystemConfig, + newConfig: SwankyConfig | SwankySystemConfig, configType: "local" | "global", projectPath?: string ) { @@ -85,23 +99,27 @@ export abstract class SwankyCommand extends Command { if (configType === "local") { configPath = - process.env.SWANKY_CONFIG ?? path.resolve(projectPath ?? ".", "swanky.config.json"); + process.env.SWANKY_CONFIG ?? + path.resolve(projectPath ?? process.cwd(), DEFAULT_CONFIG_NAME); } else { // global - configPath = findSwankySystemConfigPath() + "/swanky.config.json"; - if ("node" in config) { + configPath = getSystemConfigDirectoryPath() + `/${DEFAULT_CONFIG_NAME}`; + if ("node" in newConfig) { // If it's a SwankyConfig, extract only the system relevant parts for the global SwankySystemConfig config - config = { - defaultAccount: config.defaultAccount, - accounts: config.accounts, - networks: config.networks, + newConfig = { + defaultAccount: newConfig.defaultAccount, + accounts: newConfig.accounts, + networks: newConfig.networks, }; } - await this.mergeWithExistingSystemConfig(config, configPath); + if (existsSync(configPath)) { + const systemConfig = getSwankyConfig("global"); + this.mergeAccountsWithExistingConfig(systemConfig, newConfig); + } } this.ensureDirectoryExists(configPath); - await writeJSON(configPath, config, { spaces: 2 }); + await writeJSON(configPath, newConfig, { spaces: 2 }); } private ensureDirectoryExists(filePath: string) { @@ -111,18 +129,15 @@ export abstract class SwankyCommand extends Command { } } - private async mergeWithExistingSystemConfig(newConfig: SwankySystemConfig, configPath: string) { - if (existsSync(configPath)) { - const oldConfig = await getSwankySystemConfig(); - - newConfig.accounts.forEach((account) => { - if (!oldConfig.accounts.find((oldAccount) => oldAccount.alias === account.alias)) { - oldConfig.accounts.push(account); - } - }); + private mergeAccountsWithExistingConfig( + existingConfig: SwankySystemConfig | SwankyConfig, + newConfig: SwankySystemConfig + ) { + const accountMap = new Map( + [...existingConfig.accounts, ...newConfig.accounts].map((account) => [account.alias, account]) + ); - newConfig.accounts = oldConfig.accounts; - } + newConfig.accounts = Array.from(accountMap.values()); } protected async catch(err: Error & { exitCode?: number }): Promise { From 78e0208a9c9657d866e1cedc00992d8b00c5ce3b Mon Sep 17 00:00:00 2001 From: prxgr4mm3r Date: Fri, 2 Feb 2024 15:26:14 +0200 Subject: [PATCH 30/33] fix: Fix account storing --- src/commands/account/create.ts | 4 ++-- src/commands/account/default.ts | 2 +- src/commands/contract/deploy.ts | 9 +++++---- src/commands/contract/new.ts | 4 ++-- src/commands/node/install.ts | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 24ffc387..8f24ad08 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -90,12 +90,12 @@ export class CreateAccount extends SwankyCommand { } const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global"; - const config = configType === "global" ? getSwankyConfig("global") : this.swankyConfig; + const config = configType === "global" ? getSwankyConfig("global") : getSwankyConfig("local"); const configBuilder = new ConfigBuilder(config); configBuilder.addAccount(accountData); - if (this.swankyConfig.defaultAccount === null) { + if (config.defaultAccount === null) { configBuilder.setDefaultAccount(accountData.alias); } diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index 98c78839..e506312c 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -34,7 +34,7 @@ export class DefaultAccount extends SwankyCommand { const { args, flags } = await this.parse(DefaultAccount); const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global"; - const config = configType === "global" ? getSwankyConfig("global") : this.swankyConfig; + const config = configType === "global" ? getSwankyConfig("global") : getSwankyConfig("local"); const accountAlias = args.accountAlias ?? (await this.promptForAccountAlias(config)); this.ensureAccountExists(config, accountAlias); diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 620b0d24..56cf8d97 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -7,9 +7,9 @@ import { decrypt, AbiType, ensureAccountIsSet, - configName, + configName, getSwankyConfig, } from "../../lib/index.js"; -import { AccountData, Encrypted } from "../../types/index.js"; +import { AccountData, Encrypted, SwankyConfig } from "../../types/index.js"; import inquirer from "inquirer"; import chalk from "chalk"; import { Contract } from "../../lib/contract.js"; @@ -53,7 +53,8 @@ export class DeployContract extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(DeployContract); - const contractRecord = this.swankyConfig.contracts[args.contractName]; + const localConfig = getSwankyConfig("local") as SwankyConfig; + const contractRecord = localConfig.contracts[args.contractName]; if (!contractRecord) { throw new ConfigError( `Cannot find a contract named ${args.contractName} in "${configName()}"` @@ -154,7 +155,7 @@ export class DeployContract extends SwankyCommand { }, ]; - await this.storeConfig(this.swankyConfig, 'local'); + await this.storeConfig(localConfig, 'local'); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index c78d7284..27bf9572 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -5,7 +5,7 @@ import { checkCliDependencies, copyContractTemplateFiles, processTemplates, - getTemplates, + getTemplates, getSwankyConfig, } from "../../lib/index.js"; import { email, name, pickTemplate } from "../../lib/prompts.js"; import { paramCase, pascalCase, snakeCase } from "change-case"; @@ -97,7 +97,7 @@ export class NewContract extends SwankyCommand { await ensureDir(path.resolve(projectPath, "tests", args.contractName)); await this.spinner.runCommand(async () => { - const configBuilder = new ConfigBuilder(this.swankyConfig); + const configBuilder = new ConfigBuilder(getSwankyConfig("local")); configBuilder.addContract(args.contractName); await this.storeConfig(configBuilder.build(), "local"); }, "Writing config"); diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 74559fd4..313edd47 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -1,6 +1,6 @@ import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ux } from "@oclif/core"; -import { downloadNode, swankyNode } from "../../lib/index.js"; +import { downloadNode, getSwankyConfig, swankyNode } from "../../lib/index.js"; import path from "node:path"; import { ConfigBuilder } from "../../lib/config-builder.js"; export class InstallNode extends SwankyCommand { @@ -30,7 +30,7 @@ export class InstallNode extends SwankyCommand { const nodePath = path.resolve(projectPath, taskResult); await this.spinner.runCommand(async () => { - const configBuilder = new ConfigBuilder(this.swankyConfig); + const configBuilder = new ConfigBuilder(getSwankyConfig("local")); configBuilder.updateNodeSettings({ localPath: nodePath, polkadotPalletVersions: swankyNode.polkadotPalletVersions, From 01b7cf6d49be9dd8beeb9f89452a66c333b1e2ff Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Mon, 5 Feb 2024 10:54:15 +0100 Subject: [PATCH 31/33] feat: addContractDeployment methode added to config builder --- src/commands/contract/deploy.ts | 21 ++++++++++----------- src/lib/config-builder.ts | 21 ++++++++++++++------- src/types/index.ts | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 56cf8d97..3888c485 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -15,6 +15,7 @@ import chalk from "chalk"; import { Contract } from "../../lib/contract.js"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ApiError, ConfigError, FileError } from "../../lib/errors.js"; +import { ConfigBuilder } from "../../lib/config-builder.js"; export class DeployContract extends SwankyCommand { static description = "Deploy contract to a running node"; @@ -145,17 +146,15 @@ export class DeployContract extends SwankyCommand { }, "Deploying")) as string; await this.spinner.runCommand(async () => { - contractRecord.deployments = [ - ...contractRecord.deployments, - { - timestamp: Date.now(), - address: contractAddress, - networkUrl, - deployerAlias: accountAlias!, - }, - ]; - - await this.storeConfig(localConfig, 'local'); + const deploymentData = { + timestamp: Date.now(), + address: contractAddress, + networkUrl, + deployerAlias: accountAlias!, + }; + const configBuilder = new ConfigBuilder(localConfig); + configBuilder.addContractDeployment(args.contractName, deploymentData); + await this.storeConfig(configBuilder.build(), 'local'); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/lib/config-builder.ts b/src/lib/config-builder.ts index 0e69f1ec..1f59e71f 100644 --- a/src/lib/config-builder.ts +++ b/src/lib/config-builder.ts @@ -1,4 +1,4 @@ -import { AccountData, SwankyConfig, SwankySystemConfig } from "../index.js"; +import { AccountData, DeploymentData, SwankyConfig, SwankySystemConfig } from "../index.js"; import { snakeCase } from "change-case"; export class ConfigBuilder { @@ -25,31 +25,38 @@ export class ConfigBuilder { return this; } - updateNodeSettings(nodeSettings: Partial): ConfigBuilder { - if ('node' in this.config) { + updateNodeSettings(nodeSettings: Partial): ConfigBuilder { + if ("node" in this.config) { this.config.node = { ...this.config.node, ...nodeSettings }; } return this; } - updateContracts(contracts: SwankyConfig['contracts']): ConfigBuilder { - if ('contracts' in this.config) { + updateContracts(contracts: SwankyConfig["contracts"]): ConfigBuilder { + if ("contracts" in this.config) { this.config.contracts = { ...contracts }; } return this; } addContract(name: string, moduleName?: string): ConfigBuilder { - if ('contracts' in this.config) { + if ("contracts" in this.config) { this.config.contracts[name] = { name: name, moduleName: moduleName ?? snakeCase(name), - deployments: [] + deployments: [], }; } return this; } + addContractDeployment(name: string, data: DeploymentData): ConfigBuilder { + if ("contracts" in this.config) { + this.config.contracts[name].deployments.push(data); + } + return this; + } + build(): T { return this.config; } diff --git a/src/types/index.ts b/src/types/index.ts index e74543b3..bd013dc0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -24,7 +24,7 @@ export interface ContractData { name: string; moduleName: string; build?: BuildData; - deployments: DeploymentData[] | []; + deployments: DeploymentData[]; } export interface BuildData { From 6a574a0231b9af3a48dc161c3d724b184f122e68 Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Mon, 26 Feb 2024 16:41:01 +0100 Subject: [PATCH 32/33] chore: chain configuration into a single builder expression --- src/commands/account/create.ts | 3 +-- src/commands/account/default.ts | 5 ++--- src/commands/contract/deploy.ts | 7 ++++--- src/commands/contract/new.ts | 7 ++++--- src/commands/node/install.ts | 15 ++++++++------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/commands/account/create.ts b/src/commands/account/create.ts index 8f24ad08..cef83426 100644 --- a/src/commands/account/create.ts +++ b/src/commands/account/create.ts @@ -92,8 +92,7 @@ export class CreateAccount extends SwankyCommand { const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global"; const config = configType === "global" ? getSwankyConfig("global") : getSwankyConfig("local"); - const configBuilder = new ConfigBuilder(config); - configBuilder.addAccount(accountData); + const configBuilder = new ConfigBuilder(config).addAccount(accountData); if (config.defaultAccount === null) { configBuilder.setDefaultAccount(accountData.alias); diff --git a/src/commands/account/default.ts b/src/commands/account/default.ts index e506312c..7ffdb422 100644 --- a/src/commands/account/default.ts +++ b/src/commands/account/default.ts @@ -39,11 +39,10 @@ export class DefaultAccount extends SwankyCommand { const accountAlias = args.accountAlias ?? (await this.promptForAccountAlias(config)); this.ensureAccountExists(config, accountAlias); - const configBuilder = new ConfigBuilder(config); - configBuilder.setDefaultAccount(accountAlias); + const newConfig = new ConfigBuilder(config).setDefaultAccount(accountAlias).build(); try { - await this.storeConfig(configBuilder.build(), configType); + await this.storeConfig(newConfig, configType); } catch (cause) { throw new FileError(`Error storing default account in ${configType} config`, { cause, diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index 3888c485..5f5fb1fb 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -152,9 +152,10 @@ export class DeployContract extends SwankyCommand { networkUrl, deployerAlias: accountAlias!, }; - const configBuilder = new ConfigBuilder(localConfig); - configBuilder.addContractDeployment(args.contractName, deploymentData); - await this.storeConfig(configBuilder.build(), 'local'); + const newLocalConfig = new ConfigBuilder(localConfig) + .addContractDeployment(args.contractName, deploymentData) + .build(); + await this.storeConfig(newLocalConfig, "local"); }, "Writing config"); this.log(`Contract deployed!`); diff --git a/src/commands/contract/new.ts b/src/commands/contract/new.ts index 27bf9572..6865fe15 100644 --- a/src/commands/contract/new.ts +++ b/src/commands/contract/new.ts @@ -97,9 +97,10 @@ export class NewContract extends SwankyCommand { await ensureDir(path.resolve(projectPath, "tests", args.contractName)); await this.spinner.runCommand(async () => { - const configBuilder = new ConfigBuilder(getSwankyConfig("local")); - configBuilder.addContract(args.contractName); - await this.storeConfig(configBuilder.build(), "local"); + const newLocalConfig = new ConfigBuilder(getSwankyConfig("local")) + .addContract(args.contractName) + .build(); + await this.storeConfig(newLocalConfig, "local"); }, "Writing config"); this.log("😎 New contract successfully generated! 😎"); diff --git a/src/commands/node/install.ts b/src/commands/node/install.ts index 313edd47..fcdcb695 100644 --- a/src/commands/node/install.ts +++ b/src/commands/node/install.ts @@ -30,13 +30,14 @@ export class InstallNode extends SwankyCommand { const nodePath = path.resolve(projectPath, taskResult); await this.spinner.runCommand(async () => { - const configBuilder = new ConfigBuilder(getSwankyConfig("local")); - configBuilder.updateNodeSettings({ - localPath: nodePath, - polkadotPalletVersions: swankyNode.polkadotPalletVersions, - supportedInk: swankyNode.supportedInk, - }); - await this.storeConfig(configBuilder.build(), "local"); + const newLocalConfig = new ConfigBuilder(getSwankyConfig("local")) + .updateNodeSettings({ + localPath: nodePath, + polkadotPalletVersions: swankyNode.polkadotPalletVersions, + supportedInk: swankyNode.supportedInk, + }) + .build(); + await this.storeConfig(newLocalConfig, "local"); }, "Updating swanky config"); this.log("Swanky Node Installed successfully"); From 563c96e792921087f0036cb1231962cdc989d2fe Mon Sep 17 00:00:00 2001 From: Igor Papandinas Date: Tue, 27 Feb 2024 11:35:47 +0100 Subject: [PATCH 33/33] fix: config update for contract build verification --- src/commands/contract/verify.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/commands/contract/verify.ts b/src/commands/contract/verify.ts index e6ea3991..a0d4b85f 100644 --- a/src/commands/contract/verify.ts +++ b/src/commands/contract/verify.ts @@ -1,10 +1,12 @@ import { Args, Flags } from "@oclif/core"; import path from "node:path"; -import { ensureCargoContractVersionCompatibility, extractCargoContractVersion, Spinner } from "../../lib/index.js"; +import { ensureCargoContractVersionCompatibility, extractCargoContractVersion, getSwankyConfig, Spinner } from "../../lib/index.js"; import { pathExists } from "fs-extra/esm"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError, InputError, ProcessError } from "../../lib/errors.js"; import { spawn } from "node:child_process"; +import { ConfigBuilder } from "../../lib/config-builder.js"; +import { BuildData, SwankyConfig } from "../../index.js"; export class VerifyContract extends SwankyCommand { static description = "Verify the smart contract(s) in your contracts directory"; @@ -29,6 +31,8 @@ export class VerifyContract extends SwankyCommand { async run(): Promise { const { args, flags } = await this.parse(VerifyContract); + const localConfig = getSwankyConfig("local") as SwankyConfig; + const cargoContractVersion = extractCargoContractVersion(); if (cargoContractVersion === null) throw new InputError( @@ -112,11 +116,20 @@ export class VerifyContract extends SwankyCommand { `Verifying ${contractName} contract`, `${contractName} Contract verified successfully` ); - contractInfo.build.isVerified = true; - this.swankyConfig.contracts[contractName] = contractInfo; + await this.spinner.runCommand(async () => { + const buildData = { + ...contractInfo.build, + isVerified: true + } as BuildData; + + const newLocalConfig = new ConfigBuilder(localConfig) + .addContractBuild(args.contractName, buildData) + .build(); + + await this.storeConfig(newLocalConfig, "local"); + }, "Writing config"); - await this.storeConfig(); } } }