Skip to content

Commit

Permalink
feat: Detect build mode on deploy (#104)
Browse files Browse the repository at this point in the history
Co-authored-by: Igor Papandinas <[email protected]>
  • Loading branch information
prxgr4mm3r and ipapandinas authored Feb 26, 2024
1 parent 44da31c commit e28c7c6
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 30 deletions.
5 changes: 5 additions & 0 deletions src/commands/contract/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { pathExists } from "fs-extra/esm";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import { ensureCargoContractVersionCompatibility, extractCargoContractVersion, Spinner, storeArtifacts } from "../../lib/index.js";
import { ConfigError, InputError, ProcessError } from "../../lib/errors.js";
import { BuildMode } from "../../index.js";

export class CompileContract extends SwankyCommand<typeof CompileContract> {
static description = "Compile the smart contract(s) in your contracts directory";
Expand Down Expand Up @@ -63,6 +64,7 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
throw new InputError(`Contract folder not found at expected path`);
}

let buildMode = BuildMode.Debug;
const compilationResult = await spinner.runCommand(
async () => {
return new Promise<string>((resolve, reject) => {
Expand All @@ -73,9 +75,11 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
`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(
Expand Down Expand Up @@ -129,6 +133,7 @@ export class CompileContract extends SwankyCommand<typeof CompileContract> {
this.swankyConfig.contracts[contractName].build = {
timestamp: Date.now(),
artifactsPath,
buildMode,
isVerified: false,
};

Expand Down
33 changes: 30 additions & 3 deletions src/commands/contract/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof DeployContract> {
static description = "Deploy contract to a running node";
Expand Down Expand Up @@ -70,6 +70,33 @@ export class DeployContract extends SwankyCommand<typeof DeployContract> {
);
}

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)
Expand Down
4 changes: 2 additions & 2 deletions src/commands/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ async function detectModuleNames(copyList: CopyCandidates): Promise<CopyCandidat
entry.dirent.isDirectory() &&
(await pathExists(path.resolve(entry.path, "Cargo.toml")))
) {
const fileData = await readFile(path.resolve(entry.path, "Cargo.toml"), "utf-8");
const fileData = await readFile(path.resolve(entry.path, "Cargo.toml"), "utf8");
const toml: any = TOML.parse(fileData);
if (toml.package?.name) {
extendedEntry.moduleName = toml.package.name;
Expand Down Expand Up @@ -574,7 +574,7 @@ async function detectTests(pathToExistingProject: string): Promise<string | unde
async function readRootCargoToml(pathToProject: string) {
const rootTomlPath = path.resolve(pathToProject, "Cargo.toml");
if (!(await pathExists(rootTomlPath))) return null;
const fileData = await readFile(rootTomlPath, "utf-8");
const fileData = await readFile(rootTomlPath, "utf8");
const toml: any = TOML.parse(fileData);

if (!toml.workspace) toml.workspace = {};
Expand Down
51 changes: 26 additions & 25 deletions src/lib/contract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbiType, consts, printContractInfo } from "./index.js";
import { ContractData, DeploymentData } from "../types/index.js";
import { BuildMode, ContractData, DeploymentData } from "../types/index.js";
import { pathExists, readJSON } from "fs-extra/esm";
import path from "node:path";
import { FileError } from "./errors.js";
Expand All @@ -11,34 +11,35 @@ export class Contract {
deployments: DeploymentData[];
contractPath: string;
artifactsPath: string;
buildMode?: BuildMode;

constructor(contractRecord: ContractData) {
this.name = contractRecord.name;
this.moduleName = contractRecord.moduleName;
this.deployments = contractRecord.deployments;
this.contractPath = path.resolve("contracts", contractRecord.name);
this.artifactsPath = path.resolve(consts.ARTIFACTS_PATH, contractRecord.name);
this.buildMode = contractRecord.build?.buildMode;
}

async pathExists() {
return pathExists(this.contractPath);
}

async artifactsExist() {
const result: { result: boolean; missingPaths: string[]; missingTypes: string[] } = {
result: true,
missingPaths: [],
missingTypes: [],
};

async artifactsExist(): Promise<{ result: boolean; missingPaths: string[] }> {
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 typedContractExists(contractName: string) {
Expand All @@ -55,32 +56,32 @@ export class Contract {
}

async getABI(): Promise<AbiType> {
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<Buffer> {
const bundle = await this.getBundle();
if (bundle.source?.wasm) return bundle.source.wasm;

throw new FileError(`Cannot find wasm field in the .contract bundle!`);
}

async printInfo(): Promise<void> {
const abi = await this.getABI();
printContractInfo(abi);
}

private async ensureArtifactExists(artifactFileName: string): Promise<void> {
const artifactPath = path.resolve(this.artifactsPath, artifactFileName);
if (!(await pathExists(artifactPath))) {
throw new FileError(`Artifact file not found at path: ${artifactPath}`);
}
}
}
7 changes: 7 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ContractData {
export interface BuildData {
timestamp: number;
artifactsPath: string;
buildMode: BuildMode;
isVerified: boolean;
}

Expand All @@ -51,6 +52,12 @@ export interface SwankyConfig {
networks: Record<string, {url: string}>
}

export enum BuildMode {
Debug = "Debug",
Release = "Release",
Verifiable = "Verifiable",
}

export type SupportedPlatforms = "darwin" | "linux";
export type SupportedArch = "arm64" | "x64";

Expand Down

0 comments on commit e28c7c6

Please sign in to comment.