diff --git a/src/commands/contract/compile.ts b/src/commands/contract/compile.ts index 56129c01..9d62c152 100644 --- a/src/commands/contract/compile.ts +++ b/src/commands/contract/compile.ts @@ -5,6 +5,7 @@ import { spawn } from "node:child_process"; import { pathExists } from "fs-extra/esm"; import { SwankyCommand } from "../../lib/swankyCommand.js"; import { ConfigError, InputError, ProcessError } from "../../lib/errors.js"; +import { BuildMode } from "../../index.js"; export class CompileContract extends SwankyCommand { static description = "Compile the smart contract(s) in your contracts directory"; @@ -63,6 +64,7 @@ export class CompileContract extends SwankyCommand { throw new InputError(`Contract folder not found at expected path`); } + let buildMode = BuildMode.Debug; const compilationResult = await spinner.runCommand( async () => { return new Promise((resolve, reject) => { @@ -73,9 +75,11 @@ export class CompileContract extends SwankyCommand { `contracts/${contractName}/Cargo.toml`, ]; if (flags.release && !flags.verifiable) { + buildMode = BuildMode.Release; compileArgs.push("--release"); } if (flags.verifiable) { + buildMode = BuildMode.Verifiable; const cargoContractVersion = extractCargoContractVersion(); if (cargoContractVersion === null) throw new InputError( @@ -135,6 +139,7 @@ export class CompileContract extends SwankyCommand { this.swankyConfig.contracts[contractName].build = { timestamp: Date.now(), artifactsPath, + buildMode, isVerified: false, }; diff --git a/src/commands/contract/deploy.ts b/src/commands/contract/deploy.ts index a0b2ca0a..ac3489b4 100644 --- a/src/commands/contract/deploy.ts +++ b/src/commands/contract/deploy.ts @@ -2,13 +2,13 @@ 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 { Encrypted } from "../../types/index.js"; +import { AbiType, ChainAccount, ChainApi, decrypt, resolveNetworkUrl } from "../../lib/index.js"; +import { BuildMode, 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 { ApiError, ConfigError, FileError, ProcessError } from "../../lib/errors.js"; export class DeployContract extends SwankyCommand { static description = "Deploy contract to a running node"; @@ -70,6 +70,33 @@ export class DeployContract extends SwankyCommand { ); } + if (contract.buildMode === undefined) { + throw new ProcessError( + `Build mode is undefined for contract ${args.contractName}. Please ensure the contract is correctly compiled.` + ); + } else if (contract.buildMode !== BuildMode.Verifiable) { + await inquirer + .prompt([ + { + type: "confirm", + message: `You are deploying a not verified contract in ${ + contract.buildMode === BuildMode.Release ? "release" : "debug" + } mode. Are you sure you want to continue?`, + name: "confirm", + }, + ]) + .then((answers) => { + if (!answers.confirm) { + this.log( + `${chalk.redBright("✖")} Aborted deployment of ${chalk.yellowBright( + args.contractName + )}` + ); + process.exit(0); + } + }); + } + const accountData = this.findAccountByAlias(flags.account); const mnemonic = accountData.isDev ? (accountData.mnemonic as string) diff --git a/src/commands/init/index.ts b/src/commands/init/index.ts index 21712eba..b38239d5 100644 --- a/src/commands/init/index.ts +++ b/src/commands/init/index.ts @@ -453,7 +453,7 @@ async function detectModuleNames(copyList: CopyCandidates): Promise { + const missingPaths: string[] = []; + let result = true; + for (const artifactType of Contract.artifactTypes) { const artifactPath = path.resolve(this.artifactsPath, `${this.moduleName}${artifactType}`); - if (!(await pathExists(artifactPath))) { - result.result = false; - result.missingPaths.push(artifactPath); - result.missingTypes.push(artifactType); + result = false; + missingPaths.push(artifactPath); } } - return result; + + return { result, missingPaths }; } async getABI(): Promise { - const check = await this.artifactsExist(); - if (!check.result && check.missingTypes.includes(".json")) { - throw new FileError(`Cannot read ABI, path not found: ${check.missingPaths.toString()}`); - } - return readJSON(path.resolve(this.artifactsPath, `${this.moduleName}.json`)); + const jsonArtifactPath = `${this.moduleName}.json`; + await this.ensureArtifactExists(jsonArtifactPath); + return readJSON(path.resolve(this.artifactsPath, jsonArtifactPath)); } async getBundle() { - const check = await this.artifactsExist(); - if (!check.result && check.missingTypes.includes(".contract")) { - throw new FileError( - `Cannot read .contract bundle, path not found: ${check.missingPaths.toString()}` - ); - } - return readJSON(path.resolve(this.artifactsPath, `${this.moduleName}.contract`), 'utf-8'); + const contractArtifactPath = `${this.moduleName}.contract`; + await this.ensureArtifactExists(contractArtifactPath); + return readJSON(path.resolve(this.artifactsPath, contractArtifactPath), 'utf8'); } async getWasm(): Promise { const bundle = await this.getBundle(); if (bundle.source?.wasm) return bundle.source.wasm; - throw new FileError(`Cannot find wasm field in the .contract bundle!`); } @@ -70,4 +64,11 @@ export class Contract { const abi = await this.getABI(); printContractInfo(abi); } + + private async ensureArtifactExists(artifactFileName: string): Promise { + const artifactPath = path.resolve(this.artifactsPath, artifactFileName); + if (!(await pathExists(artifactPath))) { + throw new FileError(`Artifact file not found at path: ${artifactPath}`); + } + } } diff --git a/src/types/index.ts b/src/types/index.ts index 542a1d7f..1c7056f3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -30,6 +30,7 @@ export interface ContractData { export interface BuildData { timestamp: number; artifactsPath: string; + buildMode: BuildMode; isVerified: boolean; } @@ -51,5 +52,11 @@ export interface SwankyConfig { networks: Record } +export enum BuildMode { + Debug = "Debug", + Release = "Release", + Verifiable = "Verifiable", +} + export type SupportedPlatforms = "darwin" | "linux"; export type SupportedArch = "arm64" | "x64";