From 1570912370b889d0c80d9aa605523f479d28ef78 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 1 Jun 2023 17:22:48 +0200 Subject: [PATCH 01/51] Update tools * cairo-lang to v0.11.2 * starknet-devnet to v0.5.3 * cairo compiler to v1.1.0 --- config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index b2629fb3..4f17687a 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,5 @@ { - "CAIRO_LANG": "0.11.1.1", - "STARKNET_DEVNET": "0.5.2", - "CAIRO_COMPILER": "v1.0.0-rc0" + "CAIRO_LANG": "0.11.2", + "STARKNET_DEVNET": "0.5.3", + "CAIRO_COMPILER": "v1.1.0" } From 71febe15dcce2c84c406189da58cd68cff172306 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 12 Jun 2023 18:33:10 +0200 Subject: [PATCH 02/51] Install toml parser --- package-lock.json | 8 +++++++- package.json | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2e87e13e..e24d2015 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "^4.22.0" + "starknet": "^4.22.0", + "toml": "^3.0.0" }, "devDependencies": { "@types/chai": "^4.3.0", @@ -6962,6 +6963,11 @@ "node": ">=0.6" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/package.json b/package.json index b44fece1..7fb99d09 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "^4.22.0" + "starknet": "^4.22.0", + "toml": "^3.0.0" }, "peerDependencies": { "hardhat": "^2.14.0" From 8e10f1cf818e112d5b3f9c2c72a02cbbdb408e1c Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 12 Jun 2023 18:35:44 +0200 Subject: [PATCH 03/51] Add initial scarb support - venv only [skip ci] --- src/index.ts | 16 +++++-- src/task-actions.ts | 114 +++++++++++++++++++++++++++++++++++++++++--- src/utils.ts | 14 ++++-- 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index 2fddcb7b..cf40c065 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,7 +51,8 @@ import { starknetMigrateAction, starknetNewAccountAction, starknetDeployAccountAction, - starknetCompileCairo1Action + starknetCompileCairo1Action, + starknetBuildAction } from "./task-actions"; import { bigIntToShortStringUtil, @@ -235,7 +236,7 @@ task("starknet-compile-deprecated", "Compiles Starknet (Cairo 0) contracts") .addOptionalVariadicPositionalParam( "paths", "The paths to be used for compilation.\n" + - "Each of the provided paths is recursively looked into while searching for compilation artifacts.\n" + + "Each of the provided paths is recursively looked into while searching for source files.\n" + "If no paths are provided, the default contracts directory is traversed." ) .addOptionalParam( @@ -251,7 +252,7 @@ task("starknet-compile", "Compiles Starknet (Cairo 1) contracts") .addOptionalVariadicPositionalParam( "paths", "The paths are source files of contracts to be compiled.\n" + - "Each of the provided paths is recursively looked into while searching for compilation artifacts.\n" + + "Each of the provided paths is recursively looked into while searching for source files.\n" + "If no paths are provided, the default contracts directory is traversed." ) .addOptionalParam( @@ -268,6 +269,15 @@ task("starknet-compile", "Compiles Starknet (Cairo 1) contracts") .addFlag("addPythonicHints", "Add pythonic hints.") .setAction(starknetCompileCairo1Action); +task("starknet-build", "Builds Scarb projects under provided paths") + .addOptionalVariadicPositionalParam( + "paths", + "The paths are source files of contracts to be compiled.\n" + + "Each of the provided paths is recursively looked into while searching for Scarb projects.\n" + + "If no paths are provided, the default contracts directory is traversed." + ) + .setAction(starknetBuildAction); + extendEnvironment((hre) => { hre.starknet = { getContractFactory: async (contractPath) => { diff --git a/src/task-actions.ts b/src/task-actions.ts index 7b6316c1..43782943 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -32,6 +32,8 @@ import { createIntegratedDevnet } from "./external-server"; import { Recompiler } from "./recompiler"; import { version } from "../package.json"; import { StarknetConfig } from "./types/starknet"; +import { spawnSync } from "child_process"; +import * as toml from "toml"; function checkSourceExists(sourcePath: string): void { if (!fs.existsSync(sourcePath)) { @@ -109,9 +111,9 @@ export async function starknetCompileCairo1Action( for (const file of files) { console.log("Compiling", file); - const suffix = file.replace(rootRegex, ""); - const fileName = getFileName(suffix); - const dirPath = path.join(artifactsPath, suffix); + const dirSuffix = file.replace(rootRegex, ""); + const fileName = getFileName(dirSuffix); + const dirPath = path.join(artifactsPath, dirSuffix); const outputPath = path.join(dirPath, `${fileName}${CAIRO1_SIERRA_SUFFIX}`); fs.mkdirSync(dirPath, { recursive: true }); @@ -207,9 +209,9 @@ export async function starknetDeprecatedCompileAction( const recompiler = new Recompiler(hre); for (const file of files) { console.log("Compiling", file); - const suffix = file.replace(rootRegex, ""); - const fileName = getFileName(suffix); - const dirPath = path.join(artifactsPath, suffix); + const dirSuffix = file.replace(rootRegex, ""); + const fileName = getFileName(dirSuffix); + const dirPath = path.join(artifactsPath, dirSuffix); const outputPath = path.join(dirPath, `${fileName}.json`); const abiPath = path.join(dirPath, `${fileName}${ABI_SUFFIX}`); @@ -239,6 +241,106 @@ export async function starknetDeprecatedCompileAction( } } +export async function starknetBuildAction(args: TaskArguments, hre: HardhatRuntimeEnvironment) { + // TODO check if scarb exists + const root = hre.config.paths.root; + const rootRegex = new RegExp("^" + root); + + const defaultSourcesPath = hre.config.paths.starknetSources; + const traversablePaths: string[] = args.paths || [defaultSourcesPath]; + const artifactsPath = hre.config.paths.starknetArtifacts; + + const configFileName = "Scarb.toml"; + + let statusCode = 0; + const packageConfigPaths = []; + for (let traversablePath of traversablePaths) { + traversablePath = adaptPath(root, traversablePath); + checkSourceExists(traversablePath); + packageConfigPaths.push(...(await traverseFiles(traversablePath, configFileName))); + } + + for (const packageConfigPath of packageConfigPaths) { + const packageConfig = toml.parse(fs.readFileSync(packageConfigPath, "utf-8").toString()); + const packageName = packageConfig.package.name; + + // strip Scarb.toml from path end to get $hardhat_project_root/cairo_dir/ + const packageDir = packageConfigPath.replace(new RegExp(configFileName + "$"), ""); + console.log(`Building package ${packageName} in ${packageDir}`); + // TODO hre.starknetWrapper.scarbBuild + // TODO check if config valid; e.g. both sierra and casm specified + + const dirSuffix = packageDir.replace(rootRegex, ""); // cairo_dir/ + const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts/cairo_dir/ + + const execution = spawnSync("scarb", [ + ...["--manifest-path", packageConfigPath], + ...["--target-dir", artifactDirPath], + "build" + ]); + // TODO processExecuted(execution); + if (execution.status) { + statusCode += 1; + console.error(execution.stderr); + continue; + } + + // by default (dev mode, unlike the release mode), scarb stores artifacts in subdir "dev" + const scarbArtifactDirPath = path.join(artifactDirPath, "dev"); + // load scarb's main build artifact + const mainPackageArtifactPath = path.join( + scarbArtifactDirPath, + `${packageName}.starknet_artifacts.json` + ); + if (!fs.existsSync(mainPackageArtifactPath)) { + throw new StarknetPluginError( + `Error in building ${packageName}, could not find ${mainPackageArtifactPath}` + ); + } + const mainPackageArtifact = JSON.parse( + fs.readFileSync(mainPackageArtifactPath, "utf-8").toString() + ); + + for (const contractEntry of mainPackageArtifact.contracts) { + const scarbSierraPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.sierra); + const scarbCasmPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.casm); + // package_contract (underscore separation) + const fileName = `${contractEntry.package_name}_${contractEntry.contract_name}`; + + // artifact dir created by us, not the one created by scarb + const ourArtifactDirPath = path.join(artifactDirPath, `${fileName}.cairo`); + fs.mkdirSync(ourArtifactDirPath, { recursive: true }); + + // create artifacts compatible with our contract loading mehacnims + // to achieve this: link to scarb artifacts + const ourSierraPath = path.join( + ourArtifactDirPath, + `${fileName}${CAIRO1_SIERRA_SUFFIX}` + ); + fs.copyFileSync(scarbSierraPath, ourSierraPath); + + const ourCasmPath = path.join( + ourArtifactDirPath, + `${fileName}${CAIRO1_ASSEMBLY_SUFFIX}` + ); + fs.copyFileSync(scarbCasmPath, ourCasmPath); + + // Copy abi array from output to abiOutput + const abiOutput = path.join(ourArtifactDirPath, `${fileName}${ABI_SUFFIX}`); + initializeFile(abiOutput); + + const outputJson = JSON.parse(fs.readFileSync(scarbSierraPath, "utf-8")); + fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); + } + console.log("\tSuccessfully built ✅"); + } + + if (statusCode) { + const msg = `Failed building of ${statusCode} project${statusCode === 1 ? "" : "s"}.`; + throw new StarknetPluginError(msg); + } +} + export async function amarnaAction(args: TaskArguments, hre: HardhatRuntimeEnvironment) { await hre.amarnaDocker.run(args); } diff --git a/src/utils.ts b/src/utils.ts index 8c7970aa..5b5d720d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -98,7 +98,12 @@ export async function traverseFiles(traversable: string, fileCriteria = "*") { } else { paths.push(traversable); } - const files = paths.filter((file) => fs.lstatSync(file).isFile()); + const files = paths + .map((file) => fs.realpathSync(file)) + .filter((file) => { + const is_file = fs.lstatSync(file).isFile(); + return is_file; + }); return files; } @@ -190,8 +195,11 @@ export function isStarknetDevnet(networkName: string): boolean { export async function findPath(traversable: string, pathSegment: string) { // Relative path to artifacts can be resolved now const resolvedPath = path.resolve(path.join(traversable, pathSegment)); - if (fs.existsSync(resolvedPath) && fs.lstatSync(resolvedPath).isFile()) { - return resolvedPath; + if (fs.existsSync(resolvedPath)) { + const realPath = fs.realpathSync(resolvedPath); + if (fs.lstatSync(realPath).isFile()) { + return realPath; + } } let files = await traverseFiles(traversable); From 2dddbad8eaaec8a6b8865ac0674a137547244729 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Tue, 13 Jun 2023 15:02:45 +0200 Subject: [PATCH 04/51] Remove symlink approach leftover [skip ci] --- src/utils.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 5b5d720d..8c7970aa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -98,12 +98,7 @@ export async function traverseFiles(traversable: string, fileCriteria = "*") { } else { paths.push(traversable); } - const files = paths - .map((file) => fs.realpathSync(file)) - .filter((file) => { - const is_file = fs.lstatSync(file).isFile(); - return is_file; - }); + const files = paths.filter((file) => fs.lstatSync(file).isFile()); return files; } @@ -195,11 +190,8 @@ export function isStarknetDevnet(networkName: string): boolean { export async function findPath(traversable: string, pathSegment: string) { // Relative path to artifacts can be resolved now const resolvedPath = path.resolve(path.join(traversable, pathSegment)); - if (fs.existsSync(resolvedPath)) { - const realPath = fs.realpathSync(resolvedPath); - if (fs.lstatSync(realPath).isFile()) { - return realPath; - } + if (fs.existsSync(resolvedPath) && fs.lstatSync(resolvedPath).isFile()) { + return resolvedPath; } let files = await traverseFiles(traversable); From f349de8bdc6d51ca88746cc0c303c9d58076c222 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Wed, 14 Jun 2023 18:08:57 +0200 Subject: [PATCH 05/51] Refactor to use scarb class wrappers (docker WIP) [skip ci] --- src/index.ts | 6 +++- src/scarb-wrapper.ts | 60 ++++++++++++++++++++++++++++++++++++++ src/starknet-wrappers.ts | 1 + src/task-actions.ts | 63 +++++++++++++++++++++------------------- src/types/index.ts | 1 + src/types/starknet.ts | 1 + 6 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 src/scarb-wrapper.ts diff --git a/src/index.ts b/src/index.ts index cf40c065..6a2d51c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -269,13 +269,17 @@ task("starknet-compile", "Compiles Starknet (Cairo 1) contracts") .addFlag("addPythonicHints", "Add pythonic hints.") .setAction(starknetCompileCairo1Action); -task("starknet-build", "Builds Scarb projects under provided paths") +task("starknet-build", "Builds Scarb projects") .addOptionalVariadicPositionalParam( "paths", "The paths are source files of contracts to be compiled.\n" + "Each of the provided paths is recursively looked into while searching for Scarb projects.\n" + "If no paths are provided, the default contracts directory is traversed." ) + .addOptionalParam( + "scarbPath", + "Path to your custom local Scarb executable. Overrides the one set in the hardhat config file" + ) .setAction(starknetBuildAction); extendEnvironment((hre) => { diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts new file mode 100644 index 00000000..5b3cb8bd --- /dev/null +++ b/src/scarb-wrapper.ts @@ -0,0 +1,60 @@ +import { ProcessResult } from "@nomiclabs/hardhat-docker"; +import { spawnSync } from "child_process"; +import { TaskArguments } from "hardhat/types"; +import { StarknetConfig } from "./types/starknet"; +import { StarknetPluginError } from "./starknet-plugin-error"; +import { PLUGIN_NAME } from "./constants"; + +export abstract class ScarbWrapper { + private static instance: ScarbWrapper; + + static getInstance(cliArgs: TaskArguments, config: StarknetConfig): ScarbWrapper { + if (this.instance) { + return this.instance; + } else if (cliArgs.scarbPath) { + this.instance = new CustomScarbWrapper(cliArgs.scarbPath); + } else if (config.scarbPath) { + this.instance = new CustomScarbWrapper(config.scarbPath); + } else { + this.instance = new DockerizedScarbWrapper(); + } + return this.instance; + } + + public abstract build(packageConfigPath: string, artifactDirPath: string): ProcessResult; +} + +export class DockerizedScarbWrapper extends ScarbWrapper { + public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { + throw new Error("Method not implemented."); + } +} + +export class CustomScarbWrapper extends ScarbWrapper { + constructor(private scarbPath: string) { + super(); + + const execution = spawnSync(scarbPath, ["--version"]); + if (execution.status) { + throw new StarknetPluginError( + `Not a legal executable Scarb Path: ${scarbPath}.\n${execution.stderr.toString()}` + ); + } + + const versionString = execution.stdout.toString().trim().split("\n").join(", "); + console.log(`${PLUGIN_NAME} plugin using custom Scarb (${versionString})`); + } + + public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { + const execution = spawnSync("scarb", [ + ...["--manifest-path", packageConfigPath], + ...["--target-dir", artifactDirPath], + "build" + ]); + return { + statusCode: execution.status, + stderr: execution.stderr, + stdout: execution.stdout + }; + } +} diff --git a/src/starknet-wrappers.ts b/src/starknet-wrappers.ts index 85907d13..df3d4e4d 100644 --- a/src/starknet-wrappers.ts +++ b/src/starknet-wrappers.ts @@ -4,6 +4,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import path from "path"; import { hash, number } from "starknet"; +// TODO remove these imports and move implementation to a dedicated cairo1 wrapper class/file import { DockerCairo1Compiler, exec } from "./cairo1-compiler"; import { CAIRO1_COMPILE_BIN, diff --git a/src/task-actions.ts b/src/task-actions.ts index 43782943..1d4a354f 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -32,8 +32,8 @@ import { createIntegratedDevnet } from "./external-server"; import { Recompiler } from "./recompiler"; import { version } from "../package.json"; import { StarknetConfig } from "./types/starknet"; -import { spawnSync } from "child_process"; import * as toml from "toml"; +import { ScarbWrapper } from "./scarb-wrapper"; function checkSourceExists(sourcePath: string): void { if (!fs.existsSync(sourcePath)) { @@ -61,7 +61,7 @@ function processExecuted(executed: ProcessResult, logStatus: boolean): number { } if (logStatus) { - const finalMsg = executed.statusCode ? "Failed" : "Succeeded"; + const finalMsg = executed.statusCode ? "Failed" : "Succeeded ✅"; console.log(`\t${finalMsg}\n`); } return executed.statusCode ? 1 : 0; @@ -88,10 +88,29 @@ function getCompilerBinDir(args: TaskArguments, config: StarknetConfig): string return args?.cairo1BinDir || config.cairo1BinDir; } +function loadScarbTomlFromPath(tomlPath: string) { + return toml.parse(fs.readFileSync(tomlPath, "utf-8").toString()); + // TODO validation of toml - ideally would continue with compiling other projects even if one fails + // TODO consider adding special return type instead of any +} + +function loadScarbMainArtifact(scarbArtifactDirPath: string, packageName: string) { + const mainPackageArtifactPath = path.join( + scarbArtifactDirPath, + `${packageName}.starknet_artifacts.json` + ); + if (!fs.existsSync(mainPackageArtifactPath)) { + const msg = `Error in building ${packageName}, could not find ${mainPackageArtifactPath}`; + throw new StarknetPluginError(msg); + } + return JSON.parse(fs.readFileSync(mainPackageArtifactPath, "utf-8").toString()); +} + export async function starknetCompileCairo1Action( args: TaskArguments, hre: HardhatRuntimeEnvironment ) { + // TODO wrong order of args const binDirPath = getCompilerBinDir(hre.config.starknet, args); const root = hre.config.paths.root; @@ -242,7 +261,6 @@ export async function starknetDeprecatedCompileAction( } export async function starknetBuildAction(args: TaskArguments, hre: HardhatRuntimeEnvironment) { - // TODO check if scarb exists const root = hre.config.paths.root; const rootRegex = new RegExp("^" + root); @@ -252,7 +270,7 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const configFileName = "Scarb.toml"; - let statusCode = 0; + // collect all package configs by traversing provided paths const packageConfigPaths = []; for (let traversablePath of traversablePaths) { traversablePath = adaptPath(root, traversablePath); @@ -260,46 +278,32 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti packageConfigPaths.push(...(await traverseFiles(traversablePath, configFileName))); } + const scarbWrapper = ScarbWrapper.getInstance(args, hre.config.starknet); + + let statusCode = 0; for (const packageConfigPath of packageConfigPaths) { - const packageConfig = toml.parse(fs.readFileSync(packageConfigPath, "utf-8").toString()); + const packageConfig = loadScarbTomlFromPath(packageConfigPath); const packageName = packageConfig.package.name; - // strip Scarb.toml from path end to get $hardhat_project_root/cairo_dir/ + // strip "Scarb.toml" from path end to get $hardhat_project_root/cairo_dir/ const packageDir = packageConfigPath.replace(new RegExp(configFileName + "$"), ""); console.log(`Building package ${packageName} in ${packageDir}`); - // TODO hre.starknetWrapper.scarbBuild - // TODO check if config valid; e.g. both sierra and casm specified const dirSuffix = packageDir.replace(rootRegex, ""); // cairo_dir/ const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts/cairo_dir/ - const execution = spawnSync("scarb", [ - ...["--manifest-path", packageConfigPath], - ...["--target-dir", artifactDirPath], - "build" - ]); - // TODO processExecuted(execution); - if (execution.status) { - statusCode += 1; - console.error(execution.stderr); + const executed = scarbWrapper.build(packageConfigPath, artifactDirPath); + statusCode += processExecuted(executed, true); + if (executed.statusCode) { + // continue with compiling to casm only if compiling to sierra succeeded continue; } // by default (dev mode, unlike the release mode), scarb stores artifacts in subdir "dev" const scarbArtifactDirPath = path.join(artifactDirPath, "dev"); + // load scarb's main build artifact - const mainPackageArtifactPath = path.join( - scarbArtifactDirPath, - `${packageName}.starknet_artifacts.json` - ); - if (!fs.existsSync(mainPackageArtifactPath)) { - throw new StarknetPluginError( - `Error in building ${packageName}, could not find ${mainPackageArtifactPath}` - ); - } - const mainPackageArtifact = JSON.parse( - fs.readFileSync(mainPackageArtifactPath, "utf-8").toString() - ); + const mainPackageArtifact = loadScarbMainArtifact(scarbArtifactDirPath, packageName); for (const contractEntry of mainPackageArtifact.contracts) { const scarbSierraPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.sierra); @@ -332,7 +336,6 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const outputJson = JSON.parse(fs.readFileSync(scarbSierraPath, "utf-8")); fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); } - console.log("\tSuccessfully built ✅"); } if (statusCode) { diff --git a/src/types/index.ts b/src/types/index.ts index 12a24b56..7aaa7f98 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -385,6 +385,7 @@ export class StarknetContractFactory { const casmJson = JSON.parse(fs.readFileSync(this.casmPath, "utf-8")); if (casmJson?.compiler_version.split(".")[0] !== "1") { + // TODO doesn't allow 2.*.* const msg = ".CASM json has to contain compiler_version '1.*.*'"; throw new StarknetPluginError(msg); } diff --git a/src/types/starknet.ts b/src/types/starknet.ts index f4205994..635924cb 100644 --- a/src/types/starknet.ts +++ b/src/types/starknet.ts @@ -98,6 +98,7 @@ export type StarknetConfig = { networkUrl?: string; networkConfig?: NetworkConfig; recompile?: boolean; + scarbPath?: string; cairo1BinDir?: string; requestTimeout?: number; }; From 9abe5e1cee40f6e6537e61ec875696acb020fd5d Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 15 Jun 2023 12:40:05 +0200 Subject: [PATCH 06/51] Fix custom scarb + handle no projects [skip ci] --- src/scarb-wrapper.ts | 4 +++- src/task-actions.ts | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 5b3cb8bd..389e3157 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -34,6 +34,7 @@ export class CustomScarbWrapper extends ScarbWrapper { constructor(private scarbPath: string) { super(); + // validate const execution = spawnSync(scarbPath, ["--version"]); if (execution.status) { throw new StarknetPluginError( @@ -41,12 +42,13 @@ export class CustomScarbWrapper extends ScarbWrapper { ); } + // log const versionString = execution.stdout.toString().trim().split("\n").join(", "); console.log(`${PLUGIN_NAME} plugin using custom Scarb (${versionString})`); } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { - const execution = spawnSync("scarb", [ + const execution = spawnSync(this.scarbPath, [ ...["--manifest-path", packageConfigPath], ...["--target-dir", artifactDirPath], "build" diff --git a/src/task-actions.ts b/src/task-actions.ts index 1d4a354f..6fe5dc2c 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -271,11 +271,19 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const configFileName = "Scarb.toml"; // collect all package configs by traversing provided paths - const packageConfigPaths = []; + const packageConfigPaths: string[] = []; for (let traversablePath of traversablePaths) { traversablePath = adaptPath(root, traversablePath); checkSourceExists(traversablePath); - packageConfigPaths.push(...(await traverseFiles(traversablePath, configFileName))); + const traversionResult = await traverseFiles(traversablePath, configFileName); + packageConfigPaths.push( + ...traversionResult.filter((p) => path.basename(p) == configFileName) + ); + } + + if (!packageConfigPaths.length) { + const msg = `No projects to build. Could not find directories containing ${configFileName}`; + throw new StarknetPluginError(msg); } const scarbWrapper = ScarbWrapper.getInstance(args, hre.config.starknet); From 56651251900525ec1a2448e961df1d5f302c580f Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 15 Jun 2023 17:52:04 +0200 Subject: [PATCH 07/51] Add dockerized scarb support [WIP - mounting][skip ci] --- src/external-server/create-devnet-wrapper.ts | 11 +----- src/index.ts | 5 +-- src/scarb-wrapper.ts | 40 ++++++++++++++++++-- src/task-actions.ts | 10 +++-- src/utils.ts | 5 ++- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/external-server/create-devnet-wrapper.ts b/src/external-server/create-devnet-wrapper.ts index 5d9e128d..716e2b63 100644 --- a/src/external-server/create-devnet-wrapper.ts +++ b/src/external-server/create-devnet-wrapper.ts @@ -1,12 +1,7 @@ import { HardhatNetworkConfig, HardhatRuntimeEnvironment } from "hardhat/types"; import { StarknetPluginError } from "../starknet-plugin-error"; -import { - DEFAULT_DEVNET_DOCKER_IMAGE_TAG, - DEVNET_DOCKER_REPOSITORY, - INTEGRATED_DEVNET, - INTEGRATED_DEVNET_URL -} from "../constants"; +import { DEVNET_DOCKER_REPOSITORY, INTEGRATED_DEVNET, INTEGRATED_DEVNET_URL } from "../constants"; import { getImageTagByArch, getNetwork } from "../utils"; import { DockerDevnet } from "./docker-devnet"; import { VenvDevnet } from "./venv-devnet"; @@ -42,9 +37,7 @@ export function createIntegratedDevnet(hre: HardhatRuntimeEnvironment): External ); } - const tag = getImageTagByArch( - devnetNetwork.dockerizedVersion || DEFAULT_DEVNET_DOCKER_IMAGE_TAG - ); + const tag = getImageTagByArch(devnetNetwork.dockerizedVersion); return new DockerDevnet( { repository: DEVNET_DOCKER_REPOSITORY, diff --git a/src/index.ts b/src/index.ts index 6a2d51c2..8e889de5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,6 @@ import "./type-extensions"; import { DEFAULT_STARKNET_SOURCES_PATH, DEFAULT_STARKNET_ARTIFACTS_PATH, - CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG, CAIRO_CLI_DOCKER_REPOSITORY, AMARNA_DOCKER_REPOSITORY, AMARNA_DOCKER_IMAGE_TAG, @@ -196,9 +195,7 @@ extendEnvironment((hre) => { setVenvWrapper(hre, venvPath); } else { const repository = CAIRO_CLI_DOCKER_REPOSITORY; - const tag = getImageTagByArch( - hre.config.starknet.dockerizedVersion || CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG - ); + const tag = getImageTagByArch(hre.config.starknet.dockerizedVersion); const image = { repository, tag }; const accountPaths = extractAccountPaths(hre); diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 389e3157..03f9e4f6 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -3,7 +3,9 @@ import { spawnSync } from "child_process"; import { TaskArguments } from "hardhat/types"; import { StarknetConfig } from "./types/starknet"; import { StarknetPluginError } from "./starknet-plugin-error"; -import { PLUGIN_NAME } from "./constants"; +import { CAIRO_CLI_DOCKER_REPOSITORY, PLUGIN_NAME } from "./constants"; +import { getImageTagByArch } from "./utils"; +import path from "path"; export abstract class ScarbWrapper { private static instance: ScarbWrapper; @@ -16,7 +18,7 @@ export abstract class ScarbWrapper { } else if (config.scarbPath) { this.instance = new CustomScarbWrapper(config.scarbPath); } else { - this.instance = new DockerizedScarbWrapper(); + this.instance = new DockerizedScarbWrapper(config.dockerizedVersion); } return this.instance; } @@ -25,8 +27,40 @@ export abstract class ScarbWrapper { } export class DockerizedScarbWrapper extends ScarbWrapper { + private formattedImage: string; + + constructor(imageTag: string) { + super(); + + const repository = CAIRO_CLI_DOCKER_REPOSITORY; + const tag = getImageTagByArch(imageTag); + this.formattedImage = `${repository}:${tag}`; + + // log + console.log(`${PLUGIN_NAME} plugin using dockerized Scarb`); + } + public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { - throw new Error("Method not implemented."); + // TODO this doesn't look stable and doesn't work if artifacts dir doesn't already exist + // easiest would be to mount the whole artifacts directory + const packageDir = path.dirname(packageConfigPath); + const execution = spawnSync("docker", [ + "run", + "--rm", + ...["--mount", `type=bind,source=${packageDir},target=${packageDir}`], + ...["--mount", `type=bind,source=${artifactDirPath},target=${artifactDirPath}`], + this.formattedImage, + "scarb", + ...["--manifest-path", packageConfigPath], + ...["--target-dir", artifactDirPath], + "build" + ]); + + return { + statusCode: execution.status, + stdout: execution.stdout, + stderr: execution.stderr + }; } } diff --git a/src/task-actions.ts b/src/task-actions.ts index 6fe5dc2c..3cd1b57c 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -290,15 +290,17 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti let statusCode = 0; for (const packageConfigPath of packageConfigPaths) { + // each config path is assumed to be of format $hardhat_project_root//Scarb.toml const packageConfig = loadScarbTomlFromPath(packageConfigPath); const packageName = packageConfig.package.name; - // strip "Scarb.toml" from path end to get $hardhat_project_root/cairo_dir/ - const packageDir = packageConfigPath.replace(new RegExp(configFileName + "$"), ""); + // strip "Scarb.toml" from path end to get $hardhat_project_root// + const packageDir = path.dirname(packageConfigPath); console.log(`Building package ${packageName} in ${packageDir}`); - const dirSuffix = packageDir.replace(rootRegex, ""); // cairo_dir/ - const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts/cairo_dir/ + // not using path.basename(...) because it could be a more complex path than just the directory name + const dirSuffix = packageDir.replace(rootRegex, ""); // / + const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts// const executed = scarbWrapper.build(packageConfigPath, artifactDirPath); statusCode += processExecuted(executed, true); diff --git a/src/utils.ts b/src/utils.ts index 8c7970aa..55582328 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -26,7 +26,8 @@ import { INTEGRATED_DEVNET, INTEGRATED_DEVNET_INTERNALLY, StarknetChainId, - UDC_ADDRESS + UDC_ADDRESS, + CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG } from "./constants"; import { getContractFactoryUtil } from "./extend-utils"; import { StarknetPluginError } from "./starknet-plugin-error"; @@ -234,7 +235,7 @@ export function copyWithBigint(object: unknown): T { ); } -export function getImageTagByArch(tag: string): string { +export function getImageTagByArch(tag = CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG): string { // Check CPU architecture const arch = process.arch; if (arch === "arm64" && !tag.endsWith("-arm")) { From d41d03de6f90aa2e3c9c30f08d6ab8076c386dec Mon Sep 17 00:00:00 2001 From: FabijanC Date: Fri, 16 Jun 2023 17:13:41 +0200 Subject: [PATCH 08/51] Fix dockerized scarb support [skip ci] --- src/scarb-wrapper.ts | 33 ++++++++++++++++++++++----------- src/task-actions.ts | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 03f9e4f6..ca067841 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -1,24 +1,27 @@ import { ProcessResult } from "@nomiclabs/hardhat-docker"; import { spawnSync } from "child_process"; -import { TaskArguments } from "hardhat/types"; -import { StarknetConfig } from "./types/starknet"; +import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types"; import { StarknetPluginError } from "./starknet-plugin-error"; import { CAIRO_CLI_DOCKER_REPOSITORY, PLUGIN_NAME } from "./constants"; import { getImageTagByArch } from "./utils"; import path from "path"; +import os from "os"; export abstract class ScarbWrapper { private static instance: ScarbWrapper; - static getInstance(cliArgs: TaskArguments, config: StarknetConfig): ScarbWrapper { + static getInstance(cliArgs: TaskArguments, hre: HardhatRuntimeEnvironment): ScarbWrapper { if (this.instance) { return this.instance; } else if (cliArgs.scarbPath) { this.instance = new CustomScarbWrapper(cliArgs.scarbPath); - } else if (config.scarbPath) { - this.instance = new CustomScarbWrapper(config.scarbPath); + } else if (hre.config.starknet.scarbPath) { + this.instance = new CustomScarbWrapper(hre.config.starknet.scarbPath); } else { - this.instance = new DockerizedScarbWrapper(config.dockerizedVersion); + this.instance = new DockerizedScarbWrapper( + hre.config.starknet.dockerizedVersion, + hre.config.paths.root + ); } return this.instance; } @@ -29,7 +32,7 @@ export abstract class ScarbWrapper { export class DockerizedScarbWrapper extends ScarbWrapper { private formattedImage: string; - constructor(imageTag: string) { + constructor(imageTag: string, private projectRootPath: string) { super(); const repository = CAIRO_CLI_DOCKER_REPOSITORY; @@ -41,18 +44,26 @@ export class DockerizedScarbWrapper extends ScarbWrapper { } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { - // TODO this doesn't look stable and doesn't work if artifacts dir doesn't already exist - // easiest would be to mount the whole artifacts directory const packageDir = path.dirname(packageConfigPath); + + // the default path used by scarb, if not specified, inside the container it tries to write to /.cache + // which is not allowed for a non-root user + const globalCacheDir = path.join(os.homedir(), ".cache", "scarb"); const execution = spawnSync("docker", [ "run", "--rm", - ...["--mount", `type=bind,source=${packageDir},target=${packageDir}`], - ...["--mount", `type=bind,source=${artifactDirPath},target=${artifactDirPath}`], + ...["-v", `${packageDir}:${packageDir}`], + ...["-v", `${this.projectRootPath}:${this.projectRootPath}`], + ...["-v", `${globalCacheDir}:${globalCacheDir}`], + + // https://unix.stackexchange.com/questions/627027/files-created-by-docker-container-are-owned-by-root + ...["-u", `${os.userInfo().uid}:${os.userInfo().gid}`], + this.formattedImage, "scarb", ...["--manifest-path", packageConfigPath], ...["--target-dir", artifactDirPath], + ...["--global-cache-dir", globalCacheDir], "build" ]); diff --git a/src/task-actions.ts b/src/task-actions.ts index 3cd1b57c..422914c7 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -286,7 +286,7 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti throw new StarknetPluginError(msg); } - const scarbWrapper = ScarbWrapper.getInstance(args, hre.config.starknet); + const scarbWrapper = ScarbWrapper.getInstance(args, hre); let statusCode = 0; for (const packageConfigPath of packageConfigPaths) { From 72b5c8e965b8a857af527dcc8e31079aea426372 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 19 Jun 2023 15:42:04 +0200 Subject: [PATCH 09/51] Add scarb toml validation [skip ci] --- src/index.ts | 5 +++ src/scarb-wrapper.ts | 2 +- src/task-actions.ts | 103 ++++++++++++++++++++++++++++++++----------- src/types/index.ts | 18 ++++++++ 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/src/index.ts b/src/index.ts index 8e889de5..aa75e103 100644 --- a/src/index.ts +++ b/src/index.ts @@ -277,6 +277,11 @@ task("starknet-build", "Builds Scarb projects") "scarbPath", "Path to your custom local Scarb executable. Overrides the one set in the hardhat config file" ) + .addFlag( + "skipValidate", + "By default, your TOML config file will be validated to ensure it generates the artifacts required for later contract loading.\n" + + "Set this flag to skip the validation." + ) .setAction(starknetBuildAction); extendEnvironment((hre) => { diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index ca067841..e77c5370 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -40,7 +40,7 @@ export class DockerizedScarbWrapper extends ScarbWrapper { this.formattedImage = `${repository}:${tag}`; // log - console.log(`${PLUGIN_NAME} plugin using dockerized Scarb`); + console.log(`${PLUGIN_NAME} plugin using dockerized Scarb (${this.formattedImage})`); } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { diff --git a/src/task-actions.ts b/src/task-actions.ts index 422914c7..72e6042d 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -34,6 +34,7 @@ import { version } from "../package.json"; import { StarknetConfig } from "./types/starknet"; import * as toml from "toml"; import { ScarbWrapper } from "./scarb-wrapper"; +import { ScarbConfig } from "./types"; function checkSourceExists(sourcePath: string): void { if (!fs.existsSync(sourcePath)) { @@ -88,10 +89,46 @@ function getCompilerBinDir(args: TaskArguments, config: StarknetConfig): string return args?.cairo1BinDir || config.cairo1BinDir; } -function loadScarbTomlFromPath(tomlPath: string) { - return toml.parse(fs.readFileSync(tomlPath, "utf-8").toString()); - // TODO validation of toml - ideally would continue with compiling other projects even if one fails - // TODO consider adding special return type instead of any +class ScarbConfigError extends StarknetPluginError { + constructor(path: string, message: string, parent?: Error) { + super( + `Invalid config file ${path}: ${message}\n` + + "To skip this validation, use the --skip-validate flag in the CLI", + parent + ); + } +} + +function loadScarbTomlFromPath(tomlPath: string, validate: boolean): ScarbConfig { + const config: ScarbConfig = toml.parse(fs.readFileSync(tomlPath, "utf-8").toString()); + const packageName = config.package.name; + + if (validate) { + // it's an array of possible compilation configs + const contractTargetConfigs = config?.target["starknet-contract"] || []; + const configCandidates = contractTargetConfigs.filter( + (config) => !config.name || config.name === packageName + ); + + if (configCandidates.length === 0) { + throw new ScarbConfigError( + tomlPath, + "The name of [[target.starknet-contract]] must be left out or equal the [package] name" + ); + } else if (configCandidates.length > 1) { + // this case is handled by Scarb + } + + const contractTargetConfig = configCandidates[0]; // assume length = 1 + if (!contractTargetConfig || !contractTargetConfig.sierra || !contractTargetConfig.casm) { + throw new ScarbConfigError( + tomlPath, + "To allow later loading of this projet's contracts, " + + "your TOML file must set 'sierra' and 'casm' to `true` under [[target.starknet-contract]]" + ); + } + } + return config; } function loadScarbMainArtifact(scarbArtifactDirPath: string, packageName: string) { @@ -106,6 +143,30 @@ function loadScarbMainArtifact(scarbArtifactDirPath: string, packageName: string return JSON.parse(fs.readFileSync(mainPackageArtifactPath, "utf-8").toString()); } +async function findPackageConfigPaths( + traversablePaths: string[], + root: string, + configFileName = "Scarb.toml" +) { + // collect all package configs by traversing provided paths + const packageConfigPaths: string[] = []; + for (let traversablePath of traversablePaths) { + traversablePath = adaptPath(root, traversablePath); + checkSourceExists(traversablePath); + const traversionResult = await traverseFiles(traversablePath, configFileName); + packageConfigPaths.push( + ...traversionResult.filter((p) => path.basename(p) == configFileName) + ); + } + + if (!packageConfigPaths.length) { + const msg = `No projects to build. Could not find directories containing ${configFileName}`; + throw new StarknetPluginError(msg); + } + + return packageConfigPaths; +} + export async function starknetCompileCairo1Action( args: TaskArguments, hre: HardhatRuntimeEnvironment @@ -266,42 +327,34 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const defaultSourcesPath = hre.config.paths.starknetSources; const traversablePaths: string[] = args.paths || [defaultSourcesPath]; - const artifactsPath = hre.config.paths.starknetArtifacts; - - const configFileName = "Scarb.toml"; - - // collect all package configs by traversing provided paths - const packageConfigPaths: string[] = []; - for (let traversablePath of traversablePaths) { - traversablePath = adaptPath(root, traversablePath); - checkSourceExists(traversablePath); - const traversionResult = await traverseFiles(traversablePath, configFileName); - packageConfigPaths.push( - ...traversionResult.filter((p) => path.basename(p) == configFileName) - ); - } + const packageConfigPaths = await findPackageConfigPaths(traversablePaths, root); - if (!packageConfigPaths.length) { - const msg = `No projects to build. Could not find directories containing ${configFileName}`; - throw new StarknetPluginError(msg); - } + const artifactsPath = hre.config.paths.starknetArtifacts; const scarbWrapper = ScarbWrapper.getInstance(args, hre); let statusCode = 0; - for (const packageConfigPath of packageConfigPaths) { + for await (const packageConfigPath of packageConfigPaths) { // each config path is assumed to be of format $hardhat_project_root//Scarb.toml - const packageConfig = loadScarbTomlFromPath(packageConfigPath); + let packageConfig = null; + try { + packageConfig = loadScarbTomlFromPath(packageConfigPath, !args.skipValidate); + } catch (error) { + console.error(error); + statusCode += 1; + continue; + } const packageName = packageConfig.package.name; // strip "Scarb.toml" from path end to get $hardhat_project_root// const packageDir = path.dirname(packageConfigPath); - console.log(`Building package ${packageName} in ${packageDir}`); + console.log(`Building package ${packageName} from ${packageDir}`); // not using path.basename(...) because it could be a more complex path than just the directory name const dirSuffix = packageDir.replace(rootRegex, ""); // / const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts// + // TODO refactor to include everything after this in scarbWrapper.build const executed = scarbWrapper.build(packageConfigPath, artifactDirPath); statusCode += processExecuted(executed, true); if (executed.statusCode) { diff --git a/src/types/index.ts b/src/types/index.ts index 7aaa7f98..f41d39f0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -814,3 +814,21 @@ export class Cairo1ContractClass extends StarknetContract { return formatSpaces(JSON.stringify(abiArr)); } } + +export interface ScarbConfig { + package: { + name: string; + version: string; + }; + target: { + "starknet-contract": { + name?: string; + sierra?: boolean; + casm?: boolean; + "casm-add-pythonic-hints"?: boolean; + "allowed-libfuncs"?: boolean; + "allowed-libfuncs-deny"?: boolean; + }[]; + }; + dependencies: StringMap; +} From 1f18c9d62b9f700e212697097ed1ba7f4a2065ca Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 19 Jun 2023 15:48:49 +0200 Subject: [PATCH 10/51] Rename validation error, improve msg [skip ci] --- src/task-actions.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/task-actions.ts b/src/task-actions.ts index 72e6042d..06afa10f 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -89,7 +89,7 @@ function getCompilerBinDir(args: TaskArguments, config: StarknetConfig): string return args?.cairo1BinDir || config.cairo1BinDir; } -class ScarbConfigError extends StarknetPluginError { +class ScarbConfigValidationError extends StarknetPluginError { constructor(path: string, message: string, parent?: Error) { super( `Invalid config file ${path}: ${message}\n` + @@ -111,9 +111,9 @@ function loadScarbTomlFromPath(tomlPath: string, validate: boolean): ScarbConfig ); if (configCandidates.length === 0) { - throw new ScarbConfigError( + throw new ScarbConfigValidationError( tomlPath, - "The name of [[target.starknet-contract]] must be left out or equal the [package] name" + "Property 'name' of [[target.starknet-contract]] must be left out or equal the [package] name" ); } else if (configCandidates.length > 1) { // this case is handled by Scarb @@ -121,7 +121,7 @@ function loadScarbTomlFromPath(tomlPath: string, validate: boolean): ScarbConfig const contractTargetConfig = configCandidates[0]; // assume length = 1 if (!contractTargetConfig || !contractTargetConfig.sierra || !contractTargetConfig.casm) { - throw new ScarbConfigError( + throw new ScarbConfigValidationError( tomlPath, "To allow later loading of this projet's contracts, " + "your TOML file must set 'sierra' and 'casm' to `true` under [[target.starknet-contract]]" From 700c8e0f26e6f0f5b6efb304e8811800a8c247ea Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 19 Jun 2023 16:04:50 +0200 Subject: [PATCH 11/51] Improve code comments [skip ci] --- src/scarb-wrapper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index e77c5370..c4d974c6 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -39,15 +39,15 @@ export class DockerizedScarbWrapper extends ScarbWrapper { const tag = getImageTagByArch(imageTag); this.formattedImage = `${repository}:${tag}`; - // log console.log(`${PLUGIN_NAME} plugin using dockerized Scarb (${this.formattedImage})`); } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { const packageDir = path.dirname(packageConfigPath); - // the default path used by scarb, if not specified, inside the container it tries to write to /.cache - // which is not allowed for a non-root user + // If not specified, inside the container it tries to write cache to /.cache + // which is not allowed for a non-root user. So here we are setting it to the path used by Scarb + // in many non-docker environments const globalCacheDir = path.join(os.homedir(), ".cache", "scarb"); const execution = spawnSync("docker", [ "run", From 5c470c3110a794dddc592055d1a54e1d57b1aa7c Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 19 Jun 2023 16:20:11 +0200 Subject: [PATCH 12/51] Move TODOs to issue #384 [skip ci] * leave the TODO for build refator --- src/starknet-wrappers.ts | 2 -- src/task-actions.ts | 1 - src/types/index.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/src/starknet-wrappers.ts b/src/starknet-wrappers.ts index df3d4e4d..18f52bb3 100644 --- a/src/starknet-wrappers.ts +++ b/src/starknet-wrappers.ts @@ -3,8 +3,6 @@ import axios from "axios"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import path from "path"; import { hash, number } from "starknet"; - -// TODO remove these imports and move implementation to a dedicated cairo1 wrapper class/file import { DockerCairo1Compiler, exec } from "./cairo1-compiler"; import { CAIRO1_COMPILE_BIN, diff --git a/src/task-actions.ts b/src/task-actions.ts index 06afa10f..c2d58db3 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -171,7 +171,6 @@ export async function starknetCompileCairo1Action( args: TaskArguments, hre: HardhatRuntimeEnvironment ) { - // TODO wrong order of args const binDirPath = getCompilerBinDir(hre.config.starknet, args); const root = hre.config.paths.root; diff --git a/src/types/index.ts b/src/types/index.ts index f41d39f0..cc602eda 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -385,7 +385,6 @@ export class StarknetContractFactory { const casmJson = JSON.parse(fs.readFileSync(this.casmPath, "utf-8")); if (casmJson?.compiler_version.split(".")[0] !== "1") { - // TODO doesn't allow 2.*.* const msg = ".CASM json has to contain compiler_version '1.*.*'"; throw new StarknetPluginError(msg); } From a4bf0c9e3a93588173cbea6c9d46b997655e13a3 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 19 Jun 2023 17:36:40 +0200 Subject: [PATCH 13/51] Add scarb installation step [skip ci] --- config.json | 3 ++- scripts/test-setup.sh | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 4f17687a..30544371 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,6 @@ { "CAIRO_LANG": "0.11.2", "STARKNET_DEVNET": "0.5.3", - "CAIRO_COMPILER": "v1.1.0" + "CAIRO_COMPILER": "v1.1.0", + "SCARB_VERSION": "0.4.0" } diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index ca32e4dd..88a28907 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -1,5 +1,8 @@ #!/bin/bash +set -eu +set -o pipefail + trap 'for killable in $(jobs -p); do kill -9 $killable; done' EXIT ./scripts/ensure-python.sh @@ -27,3 +30,7 @@ fi # used by some cases ../scripts/setup-venv.sh + +# install scarb +SCARB_VERSION=$(jq -r ".SCARB_VERSION" config.json) +curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v SCARB_VERSION From 73769becc58c313c60cf51efd25f7b7119c7c94c Mon Sep 17 00:00:00 2001 From: FabijanC Date: Tue, 20 Jun 2023 16:00:00 +0200 Subject: [PATCH 14/51] Use @iarna/toml instead of toml --- package-lock.json | 14 +++++++------- package.json | 4 ++-- src/task-actions.ts | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index e24d2015..caf40707 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.8.0-alpha.2", "license": "MIT", "dependencies": { + "@iarna/toml": "^2.2.5", "@nomiclabs/hardhat-docker": "^2.0.2", "axios": "^1.0.0", "axios-retry": "^3.5.0", @@ -16,8 +17,7 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "^4.22.0", - "toml": "^3.0.0" + "starknet": "^4.22.0" }, "devDependencies": { "@types/chai": "^4.3.0", @@ -898,6 +898,11 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -6963,11 +6968,6 @@ "node": ">=0.6" } }, - "node_modules/toml": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/package.json b/package.json index 7fb99d09..d34f1151 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "author": "SpaceShard", "license": "MIT", "dependencies": { + "@iarna/toml": "^2.2.5", "@nomiclabs/hardhat-docker": "^2.0.2", "axios": "^1.0.0", "axios-retry": "^3.5.0", @@ -42,8 +43,7 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "^4.22.0", - "toml": "^3.0.0" + "starknet": "^4.22.0" }, "peerDependencies": { "hardhat": "^2.14.0" diff --git a/src/task-actions.ts b/src/task-actions.ts index c2d58db3..a66f9be9 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -32,7 +32,7 @@ import { createIntegratedDevnet } from "./external-server"; import { Recompiler } from "./recompiler"; import { version } from "../package.json"; import { StarknetConfig } from "./types/starknet"; -import * as toml from "toml"; +import * as toml from "@iarna/toml"; import { ScarbWrapper } from "./scarb-wrapper"; import { ScarbConfig } from "./types"; @@ -100,7 +100,9 @@ class ScarbConfigValidationError extends StarknetPluginError { } function loadScarbTomlFromPath(tomlPath: string, validate: boolean): ScarbConfig { - const config: ScarbConfig = toml.parse(fs.readFileSync(tomlPath, "utf-8").toString()); + const config = toml.parse( + fs.readFileSync(tomlPath, "utf-8").toString() + ) as unknown as ScarbConfig; const packageName = config.package.name; if (validate) { From 0e22d052fc357a592422bf80a9c7c1b8425d49a3 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Tue, 20 Jun 2023 17:38:46 +0200 Subject: [PATCH 15/51] Add with-scarb-dockerized [skip ci] [WIP] --- .../with-scarb-dockerized/check.ts | 25 +++++++++++++++++++ .../with-scarb-dockerized/hardhat.config.ts | 12 +++++++++ .../with-scarb-dockerized/network.json | 4 +++ test/utils/cli-functions.ts | 4 +++ 4 files changed, 45 insertions(+) create mode 100644 test/configuration-tests/with-scarb-dockerized/check.ts create mode 100644 test/configuration-tests/with-scarb-dockerized/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-dockerized/network.json diff --git a/test/configuration-tests/with-scarb-dockerized/check.ts b/test/configuration-tests/with-scarb-dockerized/check.ts new file mode 100644 index 00000000..0281478c --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized/check.ts @@ -0,0 +1,25 @@ +import { hardhatStarknetBuild, hardhatStarknetTest } from "../../utils/cli-functions"; +import { assertContains, assertExistence } from "../../utils/utils"; +import * as path from "path"; + +/** + * Testing if compilation with scarb produces the expected artifacts and if the contract can then be declared. + */ + +const buildResult = hardhatStarknetBuild(["cairo1_sample_project"]); +assertContains(buildResult.stdout, "Plugin Starknet using dockerized compiler"); + +const projectPath = path.join("starknet-artifacts", "cairo1_sample_project"); +const packageName = "sample_project_name"; +const contractNames = ["AnotherContract", "ContractSimple", "Contract", "FirstContract"]; // TODO tentative list +for (const contractName of contractNames) { + const compoundContractName = `${packageName}_${contractName}`; + const contractDirPath = path.join(projectPath, `${compoundContractName}.cairo`); + for (const extension of [".json", "_abi.json", ".casm"]) { + const artifactPath = path.join(contractDirPath, `${compoundContractName}${extension}`); + assertExistence(artifactPath); + } +} + +// TODO assert can be declared +// TODO move this somewhere else diff --git a/test/configuration-tests/with-scarb-dockerized/hardhat.config.ts b/test/configuration-tests/with-scarb-dockerized/hardhat.config.ts new file mode 100644 index 00000000..f568acd8 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized/hardhat.config.ts @@ -0,0 +1,12 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-dockerized/network.json b/test/configuration-tests/with-scarb-dockerized/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/utils/cli-functions.ts b/test/utils/cli-functions.ts index d4c1c22d..069abebe 100644 --- a/test/utils/cli-functions.ts +++ b/test/utils/cli-functions.ts @@ -48,3 +48,7 @@ export const hardhatStarknetMigrate = (args: Array, expectFailure = fals export const hardhatStarknetPluginVersion = () => { return exec("npx hardhat starknet-plugin-version"); }; + +export const hardhatStarknetBuild = (args: Array, expectFailure = false) => { + return exec(`npx hardhat starknet-build ${args.join(" ")}`, expectFailure); +}; From 1018a493ff5f795f5402aef513d356b0808e8ff4 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Wed, 21 Jun 2023 15:19:29 +0200 Subject: [PATCH 16/51] Support array in complex output [skip ci] --- src/adapt.ts | 65 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/adapt.ts b/src/adapt.ts index 0bf44f69..2a1a98de 100644 --- a/src/adapt.ts +++ b/src/adapt.ts @@ -422,6 +422,38 @@ function adaptStructInput( } } +/** + * resultIndex initially expected to be at value indicating array length + */ +function adaptArray( + result: bigint[], + resultIndex: number, + arrayType: string, + abi: starknet.Abi +) { + const elementType = arrayType.slice( + ARRAY_TYPE_PREFIX.length, + arrayType.length - ARRAY_TYPE_SUFFIX.length + ); + + const adaptedArray = []; + + // Iterate over the result array, starting with current `resultIndex` + const expectedLength = Number(result[resultIndex++]); + for (let i = 0; i < expectedLength; i++) { + // Generate a struct with each element of the array and push it to `adaptedArray` + const ret = generateComplexOutput(result, resultIndex, elementType, abi); + adaptedArray.push(ret.generatedComplex); + // Next index is the proper raw index returned from generating the struct, which accounts for nested structs + resultIndex = ret.newRawIndex; + } + + return { + adaptedArray, + newResultIndex: resultIndex + }; +} + /** * Adapts the string resulting from a Starknet CLI function call or server purpose of adapting event * This is done according to the actual output type specified by the called function. @@ -487,30 +519,9 @@ export function adaptOutputUtil( // New resultIndex is the raw index generated from the last struct adapted[outputSpec.name] = structArray; } else if (isArray(outputSpec.type)) { - const outputSpecArrayElementType = outputSpec.type.slice( - ARRAY_TYPE_PREFIX.length, - outputSpec.type.length - ARRAY_TYPE_SUFFIX.length - ); - const arrLength = Number(currentValue); - resultIndex++; - - const structArray = []; - - // Iterate over the struct array, starting with results at `resultIndex` - for (let i = 0; i < arrLength; i++) { - // Generate a struct with each element of the array and push it to `structArray` - const ret = generateComplexOutput( - result, - resultIndex, - outputSpecArrayElementType, - abi - ); - structArray.push(ret.generatedComplex); - // Next index is the proper raw index returned from generating the struct, which accounts for nested structs - resultIndex = ret.newRawIndex; - } - // New resultIndex is the raw index generated from the last struct - adapted[outputSpec.name] = structArray; + const ret = adaptArray(result, resultIndex, outputSpec.type, abi); + resultIndex = ret.newResultIndex; + adapted[outputSpec.name] = ret.adaptedArray; } else { const ret = generateComplexOutput(result, resultIndex, outputSpec.type, abi); adapted[outputSpec.name] = ret.generatedComplex; @@ -578,10 +589,14 @@ function generateComplexOutput(raw: bigint[], rawIndex: number, type: string, ab rawIndex = ret.newRawIndex; } } + } else if (isArray(type)) { + const ret = adaptArray(raw, rawIndex, type, abi); + generatedComplex = ret.adaptedArray; + rawIndex = ret.newResultIndex; } else { // struct if (!(type in abi)) { - throw new StarknetPluginError(`Type ${type} not present in ABI.`); + throw new StarknetPluginError(`Type ${type} not present in ABI.` + JSON.stringify(abi)); } generatedComplex = {}; From 7eaa8f9e111526e731dfa3fe5a321aeaf96c0e79 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Wed, 21 Jun 2023 18:36:56 +0200 Subject: [PATCH 17/51] Add tests [skip ci] --- scripts/test-setup.sh | 3 + src/index.ts | 4 +- src/scarb-wrapper.ts | 16 ++--- src/task-actions.ts | 52 +++++++++------- src/types/starknet.ts | 2 +- .../with-scarb-cli-path/check.ts | 10 +++ .../with-scarb-cli-path/hardhat.config.ts | 12 ++++ .../with-scarb-cli-path/network.json | 4 ++ .../check.ts | 15 +++++ .../hardhat.config.ts | 12 ++++ .../multiple_contracts_invalid.cairo | 17 +++++ .../network.json | 4 ++ .../Scarb-invalid.toml | 13 ++++ .../check.ts | 21 +++++++ .../hardhat.config.ts | 12 ++++ .../network.json | 4 ++ .../check.ts | 16 +++++ .../hardhat.config.ts | 12 ++++ .../network.json | 4 ++ .../with-scarb-dockerized/check.ts | 30 +++------ .../with-scarb-path/check.ts | 9 +++ .../with-scarb-path/hardhat.config.ts | 13 ++++ .../with-scarb-path/network.json | 4 ++ .../relative-artifact-test/check.ts | 4 +- test/utils/scarb-utils.ts | 62 +++++++++++++++++++ test/utils/utils.ts | 12 +++- www/docs/dev.md | 3 +- 27 files changed, 309 insertions(+), 61 deletions(-) create mode 100644 test/configuration-tests/with-scarb-cli-path/check.ts create mode 100644 test/configuration-tests/with-scarb-cli-path/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-cli-path/network.json create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-invalid-config/network.json create mode 100644 test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json create mode 100644 test/configuration-tests/with-scarb-path/check.ts create mode 100644 test/configuration-tests/with-scarb-path/hardhat.config.ts create mode 100644 test/configuration-tests/with-scarb-path/network.json create mode 100644 test/utils/scarb-utils.ts diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index 88a28907..2bd83c64 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -5,6 +5,9 @@ set -o pipefail trap 'for killable in $(jobs -p); do kill -9 $killable; done' EXIT +# log versions +./scripts/versions.sh + ./scripts/ensure-python.sh # setup example repo diff --git a/src/index.ts b/src/index.ts index aa75e103..f8db5d28 100644 --- a/src/index.ts +++ b/src/index.ts @@ -274,8 +274,8 @@ task("starknet-build", "Builds Scarb projects") "If no paths are provided, the default contracts directory is traversed." ) .addOptionalParam( - "scarbPath", - "Path to your custom local Scarb executable. Overrides the one set in the hardhat config file" + "scarbCommand", + "Your local Scarb command or path to the executable file. Overrides the one set in the hardhat config file" ) .addFlag( "skipValidate", diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index c4d974c6..47945cf9 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -13,10 +13,10 @@ export abstract class ScarbWrapper { static getInstance(cliArgs: TaskArguments, hre: HardhatRuntimeEnvironment): ScarbWrapper { if (this.instance) { return this.instance; - } else if (cliArgs.scarbPath) { - this.instance = new CustomScarbWrapper(cliArgs.scarbPath); - } else if (hre.config.starknet.scarbPath) { - this.instance = new CustomScarbWrapper(hre.config.starknet.scarbPath); + } else if (cliArgs.scarbCommand) { + this.instance = new CustomScarbWrapper(cliArgs.scarbCommand); + } else if (hre.config.starknet.scarbCommand) { + this.instance = new CustomScarbWrapper(hre.config.starknet.scarbCommand); } else { this.instance = new DockerizedScarbWrapper( hre.config.starknet.dockerizedVersion, @@ -76,14 +76,14 @@ export class DockerizedScarbWrapper extends ScarbWrapper { } export class CustomScarbWrapper extends ScarbWrapper { - constructor(private scarbPath: string) { + constructor(private scarbCommand: string) { super(); // validate - const execution = spawnSync(scarbPath, ["--version"]); + const execution = spawnSync(scarbCommand, ["--version"]); if (execution.status) { throw new StarknetPluginError( - `Not a legal executable Scarb Path: ${scarbPath}.\n${execution.stderr.toString()}` + `Not a legal executable Scarb command: ${scarbCommand}.\n${execution.stderr.toString()}` ); } @@ -93,7 +93,7 @@ export class CustomScarbWrapper extends ScarbWrapper { } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { - const execution = spawnSync(this.scarbPath, [ + const execution = spawnSync(this.scarbCommand, [ ...["--manifest-path", packageConfigPath], ...["--target-dir", artifactDirPath], "build" diff --git a/src/task-actions.ts b/src/task-actions.ts index a66f9be9..dbda9a86 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -370,8 +370,6 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const mainPackageArtifact = loadScarbMainArtifact(scarbArtifactDirPath, packageName); for (const contractEntry of mainPackageArtifact.contracts) { - const scarbSierraPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.sierra); - const scarbCasmPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.casm); // package_contract (underscore separation) const fileName = `${contractEntry.package_name}_${contractEntry.contract_name}`; @@ -379,26 +377,38 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const ourArtifactDirPath = path.join(artifactDirPath, `${fileName}.cairo`); fs.mkdirSync(ourArtifactDirPath, { recursive: true }); - // create artifacts compatible with our contract loading mehacnims - // to achieve this: link to scarb artifacts - const ourSierraPath = path.join( - ourArtifactDirPath, - `${fileName}${CAIRO1_SIERRA_SUFFIX}` - ); - fs.copyFileSync(scarbSierraPath, ourSierraPath); - - const ourCasmPath = path.join( - ourArtifactDirPath, - `${fileName}${CAIRO1_ASSEMBLY_SUFFIX}` - ); - fs.copyFileSync(scarbCasmPath, ourCasmPath); - - // Copy abi array from output to abiOutput - const abiOutput = path.join(ourArtifactDirPath, `${fileName}${ABI_SUFFIX}`); - initializeFile(abiOutput); + // We want to create artifacts compatible with our contract loading mehacnims. + // To achieve this, we will now copy scarb artifacts + + // this is false if user skipped validation + if (contractEntry.artifacts.sierra) { + const scarbSierraPath = path.join( + scarbArtifactDirPath, + contractEntry.artifacts.sierra + ); + const ourSierraPath = path.join( + ourArtifactDirPath, + `${fileName}${CAIRO1_SIERRA_SUFFIX}` + ); + fs.copyFileSync(scarbSierraPath, ourSierraPath); + + // Copy abi array from output to abiOutput + const abiOutput = path.join(ourArtifactDirPath, `${fileName}${ABI_SUFFIX}`); + initializeFile(abiOutput); + + const outputJson = JSON.parse(fs.readFileSync(scarbSierraPath, "utf-8")); + fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); + } - const outputJson = JSON.parse(fs.readFileSync(scarbSierraPath, "utf-8")); - fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); + // this is false if user skipped validation + if (contractEntry.artifacts.casm) { + const scarbCasmPath = path.join(scarbArtifactDirPath, contractEntry.artifacts.casm); + const ourCasmPath = path.join( + ourArtifactDirPath, + `${fileName}${CAIRO1_ASSEMBLY_SUFFIX}` + ); + fs.copyFileSync(scarbCasmPath, ourCasmPath); + } } } diff --git a/src/types/starknet.ts b/src/types/starknet.ts index 635924cb..9d0e574c 100644 --- a/src/types/starknet.ts +++ b/src/types/starknet.ts @@ -98,7 +98,7 @@ export type StarknetConfig = { networkUrl?: string; networkConfig?: NetworkConfig; recompile?: boolean; - scarbPath?: string; + scarbCommand?: string; cairo1BinDir?: string; requestTimeout?: number; }; diff --git a/test/configuration-tests/with-scarb-cli-path/check.ts b/test/configuration-tests/with-scarb-cli-path/check.ts new file mode 100644 index 00000000..b3b52c8d --- /dev/null +++ b/test/configuration-tests/with-scarb-cli-path/check.ts @@ -0,0 +1,10 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbAssertions } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; + +const projectName = "cairo1_sample_project"; +// override the default of using dockerized Scarb +const buildResult = hardhatStarknetBuild([projectName, "--scarb-command", "scarb"]); +assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); + +scarbAssertions(projectName); diff --git a/test/configuration-tests/with-scarb-cli-path/hardhat.config.ts b/test/configuration-tests/with-scarb-cli-path/hardhat.config.ts new file mode 100644 index 00000000..f568acd8 --- /dev/null +++ b/test/configuration-tests/with-scarb-cli-path/hardhat.config.ts @@ -0,0 +1,12 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-cli-path/network.json b/test/configuration-tests/with-scarb-cli-path/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-cli-path/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts new file mode 100644 index 00000000..f96a009f --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts @@ -0,0 +1,15 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { assertContains } from "../../utils/utils"; +import * as fs from "fs"; +import * as path from "path"; + +const projectName = "cairo1_sample_project"; + +// override a cairo source file with an invalid one +const invalidConfigFilePath = path.join(__dirname, "multiple_contracts_invalid.cairo"); +fs.copyFileSync(invalidConfigFilePath, path.join(projectName, "src", "multiple_contracts.cairo")); + +// expect failure +console.log("Expecting rejection if invalid cairo source file"); +const buildResult = hardhatStarknetBuild([projectName], true); +assertContains(buildResult.stderr, "Failed building of 1 project"); diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts new file mode 100644 index 00000000..f568acd8 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts @@ -0,0 +1,12 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo new file mode 100644 index 00000000..322beb21 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo @@ -0,0 +1,17 @@ +// an invalid contract by virtue of invalid spaces in the mod name + +#[contract] +mod First Contract { + #[view] + fn greet() -> felt252 { + return 'Hello from First'; + } +} + +#[contract] +mod AnotherContract { + #[view] + fn get_balance() -> felt252 { + return 'Hello from Another'; + } +} diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml b/test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml new file mode 100644 index 00000000..ada46c74 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml @@ -0,0 +1,13 @@ +[package] +name = "sample_package_name" +version = "0.1.0" + +[[target.starknet-contract]] +# Enable Sierra codegen. +sierra = true + +# Enable CASM codegen. +casm = false + +[dependencies] +starknet = ">=1.1.0" diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts b/test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts new file mode 100644 index 00000000..2dd35113 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts @@ -0,0 +1,21 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbArtifactsAssertion } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; +import * as fs from "fs"; +import * as path from "path"; + +const projectName = "cairo1_sample_project"; + +// override the config file with an invalid one - doesn't specify casm generation +const invalidConfigFilePath = path.join(__dirname, "Scarb-invalid.toml"); +fs.copyFileSync(invalidConfigFilePath, path.join(projectName, "Scarb.toml")); + +// expect failure +console.log("Expecting rejection if invalid config file"); +const buildResult = hardhatStarknetBuild([projectName], true); +assertContains(buildResult.stderr, "Invalid config file"); + +// expect to pass if skipping validation +console.log("Expecting success if skipping validation"); +hardhatStarknetBuild([projectName, "--skip-validate"], false); +scarbArtifactsAssertion(projectName, undefined, undefined, [".json", "_abi.json"]); diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts b/test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts new file mode 100644 index 00000000..f568acd8 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts @@ -0,0 +1,12 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/network.json b/test/configuration-tests/with-scarb-dockerized-invalid-config/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-invalid-config/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts b/test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts new file mode 100644 index 00000000..af94b8f6 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts @@ -0,0 +1,16 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbArtifactsAssertion } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; +import * as fs from "fs"; + +// generate another project - a copy of the sample one +const projectName = "cairo1_sample_project"; +const copiedProjectName = "cairo1_copied_project"; + +fs.cpSync(projectName, copiedProjectName, { recursive: true }); + +const buildResult = hardhatStarknetBuild([projectName, copiedProjectName]); +assertContains(buildResult.stdout, "Starknet plugin using dockerized Scarb"); + +scarbArtifactsAssertion(projectName); +scarbArtifactsAssertion(copiedProjectName); diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts b/test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts new file mode 100644 index 00000000..f568acd8 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts @@ -0,0 +1,12 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json b/test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/configuration-tests/with-scarb-dockerized/check.ts b/test/configuration-tests/with-scarb-dockerized/check.ts index 0281478c..94ad5ca9 100644 --- a/test/configuration-tests/with-scarb-dockerized/check.ts +++ b/test/configuration-tests/with-scarb-dockerized/check.ts @@ -1,25 +1,9 @@ -import { hardhatStarknetBuild, hardhatStarknetTest } from "../../utils/cli-functions"; -import { assertContains, assertExistence } from "../../utils/utils"; -import * as path from "path"; +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbAssertions } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; -/** - * Testing if compilation with scarb produces the expected artifacts and if the contract can then be declared. - */ +const projectName = "cairo1_sample_project"; +const buildResult = hardhatStarknetBuild([projectName]); +assertContains(buildResult.stdout, "Starknet plugin using dockerized Scarb"); -const buildResult = hardhatStarknetBuild(["cairo1_sample_project"]); -assertContains(buildResult.stdout, "Plugin Starknet using dockerized compiler"); - -const projectPath = path.join("starknet-artifacts", "cairo1_sample_project"); -const packageName = "sample_project_name"; -const contractNames = ["AnotherContract", "ContractSimple", "Contract", "FirstContract"]; // TODO tentative list -for (const contractName of contractNames) { - const compoundContractName = `${packageName}_${contractName}`; - const contractDirPath = path.join(projectPath, `${compoundContractName}.cairo`); - for (const extension of [".json", "_abi.json", ".casm"]) { - const artifactPath = path.join(contractDirPath, `${compoundContractName}${extension}`); - assertExistence(artifactPath); - } -} - -// TODO assert can be declared -// TODO move this somewhere else +scarbAssertions(projectName); diff --git a/test/configuration-tests/with-scarb-path/check.ts b/test/configuration-tests/with-scarb-path/check.ts new file mode 100644 index 00000000..a4f80186 --- /dev/null +++ b/test/configuration-tests/with-scarb-path/check.ts @@ -0,0 +1,9 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbAssertions } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; + +const projectName = "cairo1_sample_project"; +const buildResult = hardhatStarknetBuild([projectName]); +assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); + +scarbAssertions(projectName); diff --git a/test/configuration-tests/with-scarb-path/hardhat.config.ts b/test/configuration-tests/with-scarb-path/hardhat.config.ts new file mode 100644 index 00000000..c42d100e --- /dev/null +++ b/test/configuration-tests/with-scarb-path/hardhat.config.ts @@ -0,0 +1,13 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + network: process.env.NETWORK, + scarb: "scarb" + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/configuration-tests/with-scarb-path/network.json b/test/configuration-tests/with-scarb-path/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/configuration-tests/with-scarb-path/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} diff --git a/test/general-tests/relative-artifact-test/check.ts b/test/general-tests/relative-artifact-test/check.ts index 8d73abea..4cf4d1c9 100644 --- a/test/general-tests/relative-artifact-test/check.ts +++ b/test/general-tests/relative-artifact-test/check.ts @@ -1,8 +1,8 @@ import { hardhatStarknetCompileDeprecated, hardhatStarknetTest } from "../../utils/cli-functions"; -import { exec } from "../../utils/utils"; +import * as fs from "fs"; hardhatStarknetCompileDeprecated("contracts/contract.cairo contracts/util.cairo".split(" ")); -exec("cp -a starknet-artifacts/contracts test/test-artifacts"); +fs.cpSync("starknet-artifacts/contracts", "test/test-artifacts", { recursive: true }); hardhatStarknetTest("--no-compile test/relative-artifacts.test.ts".split(" ")); diff --git a/test/utils/scarb-utils.ts b/test/utils/scarb-utils.ts new file mode 100644 index 00000000..984094ba --- /dev/null +++ b/test/utils/scarb-utils.ts @@ -0,0 +1,62 @@ +import path from "path"; +import { assertExistence, assertNotEmpty } from "./utils"; +import { hardhatStarknetRun, hardhatStarknetTest } from "./cli-functions"; + +const DEFAULT_PACKAGE_NAME = "sample_package_name"; + +/** + * Assert that artifacts of a project exist + * @param projectName the name of the project + */ +export function scarbArtifactsAssertion( + projectName: string, + packageName = DEFAULT_PACKAGE_NAME, + contractNames = ["FirstContract", "AnotherContract", "FibContract"], + extensions = [".json", "_abi.json", ".casm"] +) { + const projectPath = path.join("starknet-artifacts", projectName); + for (const contractName of contractNames) { + const compoundContractName = `${packageName}_${contractName}`; + const contractDirPath = path.join(projectPath, `${compoundContractName}.cairo`); + for (const extension of extensions) { + const artifactPath = path.join(contractDirPath, `${compoundContractName}${extension}`); + assertExistence(artifactPath); + assertNotEmpty(artifactPath); + } + } +} + +function assertDeclarable( + packageName = DEFAULT_PACKAGE_NAME, + contractNames = ["FirstContract", "AnotherContract"] +) { + // attempt declaration for all contracts except FibContract + for (const contractName of contractNames) { + const compoundContractName = `${packageName}_${contractName}`; + + // the script requires the environment variable, but let's store it just in case + const oldEnvVarValue = process.env.DECLARABLE_CONTRACT; + process.env.DECLARABLE_CONTRACT = compoundContractName; + try { + hardhatStarknetRun(["scripts/declare.ts"]); + } finally { + // restore + process.env.DECLARABLE_CONTRACT = oldEnvVarValue; + } + } +} + +/** + * Asserts existence, non-emptiness, declarableness, interactivity of the contracts + * from a project built by Scarb. + * @param projectName the name of the built project + */ +export function scarbAssertions(projectName: string, packageName = DEFAULT_PACKAGE_NAME) { + scarbArtifactsAssertion(projectName); + + assertDeclarable(packageName); + + // attempt full declare+deploy+call on FibContract + // if it was declared earlier with the rest, this script would fail + hardhatStarknetTest(["test/cairo1/fib-contract.test.ts"]); +} diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 4da6b0b5..c305986a 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -1,6 +1,6 @@ import axios from "axios"; import assert, { AssertionError } from "assert"; -import { existsSync, rmSync } from "fs"; +import { existsSync, rmSync, statSync } from "fs"; import shell from "shelljs"; import { DEVNET_URL } from "../constants/constants"; @@ -50,7 +50,7 @@ export function rmrfSync(path: string) { } export function assertEqual(val1: unknown, val2: unknown, msg?: string) { - assert.equal(val1, val2, msg); + assert.strictEqual(val1, val2, msg); } export function assertNotEqual(val1: unknown, val2: unknown, msg?: string) { @@ -63,3 +63,11 @@ export function assertExistence(path: string, expected = true) { throw new AssertionError({ message }); } } + +export function assertNotEmpty(path: string) { + const stat = statSync(path); + if (stat.size <= 0) { + const message = `Size of ${path} expected to be > 0`; + throw new AssertionError({ message }); + } +} diff --git a/www/docs/dev.md b/www/docs/dev.md index 674c7013..0445607d 100644 --- a/www/docs/dev.md +++ b/www/docs/dev.md @@ -67,8 +67,7 @@ $ npm run test-general-tests -- declare-test ### Executing individual tests with dockerized environnement -If you only use dockerized environnement you don't need to install dependencies locally. -Therefore you can run `declare-test` test case in `general-tests` test group from `starknet-hardhat-example` directory like this : +If you are only running Devnet in dockerized mode, you don't need to install all the dev tools locally. With a properly set up `starknet-hardhat-example` (read more [here](#Set-up-the-example-repository)), you can position yourself in that repository and to execute the `declare-test` case of the `general-tests` group, you can run: ```sh $ npx ts-node STARKNET_HARDHAT_PLUGIN_PATH/test/general-tests/declare-test/check.ts From 70ca814b9f72641ab13bfa5200ee2b1a4935a8a7 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Wed, 21 Jun 2023 18:38:57 +0200 Subject: [PATCH 18/51] Remove refactoring TODO --- src/adapt.ts | 7 +------ src/task-actions.ts | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/adapt.ts b/src/adapt.ts index 2a1a98de..f2923a31 100644 --- a/src/adapt.ts +++ b/src/adapt.ts @@ -425,12 +425,7 @@ function adaptStructInput( /** * resultIndex initially expected to be at value indicating array length */ -function adaptArray( - result: bigint[], - resultIndex: number, - arrayType: string, - abi: starknet.Abi -) { +function adaptArray(result: bigint[], resultIndex: number, arrayType: string, abi: starknet.Abi) { const elementType = arrayType.slice( ARRAY_TYPE_PREFIX.length, arrayType.length - ARRAY_TYPE_SUFFIX.length diff --git a/src/task-actions.ts b/src/task-actions.ts index dbda9a86..c61063ea 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -355,7 +355,6 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const dirSuffix = packageDir.replace(rootRegex, ""); // / const artifactDirPath = path.join(artifactsPath, dirSuffix); // starknet-artifacts// - // TODO refactor to include everything after this in scarbWrapper.build const executed = scarbWrapper.build(packageConfigPath, artifactDirPath); statusCode += processExecuted(executed, true); if (executed.statusCode) { From 13db1df3815a4b375058c205d553f69ff6fe5055 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 09:29:18 +0200 Subject: [PATCH 19/51] Fix minor shell script errors --- scripts/test-setup.sh | 2 +- scripts/versions.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index 2bd83c64..41c50b09 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -35,5 +35,5 @@ fi ../scripts/setup-venv.sh # install scarb -SCARB_VERSION=$(jq -r ".SCARB_VERSION" config.json) +SCARB_VERSION=$(jq -r ".SCARB_VERSION" ../config.json) curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v SCARB_VERSION diff --git a/scripts/versions.sh b/scripts/versions.sh index 834f6579..2c062214 100755 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -8,8 +8,8 @@ echo "node: $(node --version)" echo "npm: $(npm --version)" #these two commands may return different versions (e.g. if using circleci/node and remote docker) -echo "docker: $(docker --version)" -docker version +echo "docker --version: $(docker --version)" +echo "docker version: $(docker version)" echo "python3: $(python3 --version)" echo "pip3: $(pip3 --version)" From 5de3113e7c66a47c8fcbb08b4693ff83774b14f3 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 09:31:12 +0200 Subject: [PATCH 20/51] Change example repo branch --- scripts/test-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index 41c50b09..a0f16ea4 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -12,7 +12,7 @@ trap 'for killable in $(jobs -p); do kill -9 $killable; done' EXIT # setup example repo rm -rf starknet-hardhat-example -EXAMPLE_REPO_BRANCH="plugin" +EXAMPLE_REPO_BRANCH="adapt-0.11.2" if [[ "$CIRCLE_BRANCH" == "master" ]] && [[ "$EXAMPLE_REPO_BRANCH" != "plugin" ]]; then echo "Invalid example repo branch: $EXAMPLE_REPO_BRANCH" exit 1 From aa9bd5e1e4f05362078f4a1e42abb84c8700678d Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 09:37:41 +0200 Subject: [PATCH 21/51] Remove python3.8 from caching --- .circleci/config.yml | 2 -- www/docs/intro.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0738bf8b..796059da 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -116,7 +116,6 @@ aliases: name: "Save cairo-lang Cache" key: cairo-lang-cache-{{ arch }}-v1-{{ checksum "/tmp/cairo-lang-version" }} paths: - - /usr/python3.8/dist-packages/cairo-lang - /usr/python3.9/dist-packages/cairo-lang - /usr/local/bin/starknet - /usr/local/bin/starknet-compile @@ -133,7 +132,6 @@ aliases: - /opt/circleci/.pyenv/versions - /opt/circleci/.pyenv/shims/starknet-devnet - /usr/local/bin/starknet-devnet - - /usr/local/lib/python3.8/site-packages - /usr/local/lib/python3.9/site-packages # Commands diff --git a/www/docs/intro.md b/www/docs/intro.md index 86b0102e..c4533e98 100644 --- a/www/docs/intro.md +++ b/www/docs/intro.md @@ -688,7 +688,7 @@ pip install openzeppelin-cairo-contracts ```typescript paths: { // this directory contains the openzeppelin directory - cairoPaths: ["path/to/cairo_venv/lib/python3.8/site-packages"], + cairoPaths: ["path/to/cairo_venv/lib/python3.9/site-packages"], } ``` From f058e72edf5d17c9762b425a528fa4223ee13049 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 09:42:21 +0200 Subject: [PATCH 22/51] Fix scarb installation --- scripts/test-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index a0f16ea4..fa5c4511 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -36,4 +36,4 @@ fi # install scarb SCARB_VERSION=$(jq -r ".SCARB_VERSION" ../config.json) -curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v SCARB_VERSION +curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v "$SCARB_VERSION" From 8dcc42eb39fa077e2f3edb89fea70a84a55749e3 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 10:25:47 +0200 Subject: [PATCH 23/51] Fix getting of docker image --- src/external-server/create-devnet-wrapper.ts | 4 ++-- src/index.ts | 4 ++-- src/scarb-wrapper.ts | 4 ++-- src/utils.ts | 13 +++++++++++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/external-server/create-devnet-wrapper.ts b/src/external-server/create-devnet-wrapper.ts index 716e2b63..844b8830 100644 --- a/src/external-server/create-devnet-wrapper.ts +++ b/src/external-server/create-devnet-wrapper.ts @@ -2,7 +2,7 @@ import { HardhatNetworkConfig, HardhatRuntimeEnvironment } from "hardhat/types"; import { StarknetPluginError } from "../starknet-plugin-error"; import { DEVNET_DOCKER_REPOSITORY, INTEGRATED_DEVNET, INTEGRATED_DEVNET_URL } from "../constants"; -import { getImageTagByArch, getNetwork } from "../utils"; +import { getCairoCliImageTagByArch, getNetwork } from "../utils"; import { DockerDevnet } from "./docker-devnet"; import { VenvDevnet } from "./venv-devnet"; import { ExternalServer } from "./external-server"; @@ -37,7 +37,7 @@ export function createIntegratedDevnet(hre: HardhatRuntimeEnvironment): External ); } - const tag = getImageTagByArch(devnetNetwork.dockerizedVersion); + const tag = getCairoCliImageTagByArch(devnetNetwork.dockerizedVersion); return new DockerDevnet( { repository: DEVNET_DOCKER_REPOSITORY, diff --git a/src/index.ts b/src/index.ts index f8db5d28..addd582d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,9 +34,9 @@ import { import { adaptPath, getAccountPath, + getCairoCliImageTagByArch, getDefaultHardhatNetworkConfig, getDefaultHttpNetworkConfig, - getImageTagByArch, getNetwork } from "./utils"; import { DockerWrapper, VenvWrapper } from "./starknet-wrappers"; @@ -195,7 +195,7 @@ extendEnvironment((hre) => { setVenvWrapper(hre, venvPath); } else { const repository = CAIRO_CLI_DOCKER_REPOSITORY; - const tag = getImageTagByArch(hre.config.starknet.dockerizedVersion); + const tag = getCairoCliImageTagByArch(hre.config.starknet.dockerizedVersion); const image = { repository, tag }; const accountPaths = extractAccountPaths(hre); diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 47945cf9..fff1301c 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -3,7 +3,7 @@ import { spawnSync } from "child_process"; import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types"; import { StarknetPluginError } from "./starknet-plugin-error"; import { CAIRO_CLI_DOCKER_REPOSITORY, PLUGIN_NAME } from "./constants"; -import { getImageTagByArch } from "./utils"; +import { getCairoCliImageTagByArch } from "./utils"; import path from "path"; import os from "os"; @@ -36,7 +36,7 @@ export class DockerizedScarbWrapper extends ScarbWrapper { super(); const repository = CAIRO_CLI_DOCKER_REPOSITORY; - const tag = getImageTagByArch(imageTag); + const tag = getCairoCliImageTagByArch(imageTag); this.formattedImage = `${repository}:${tag}`; console.log(`${PLUGIN_NAME} plugin using dockerized Scarb (${this.formattedImage})`); diff --git a/src/utils.ts b/src/utils.ts index 55582328..9a2ca555 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -27,7 +27,8 @@ import { INTEGRATED_DEVNET_INTERNALLY, StarknetChainId, UDC_ADDRESS, - CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG + CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG, + DEFAULT_DEVNET_DOCKER_IMAGE_TAG } from "./constants"; import { getContractFactoryUtil } from "./extend-utils"; import { StarknetPluginError } from "./starknet-plugin-error"; @@ -235,7 +236,7 @@ export function copyWithBigint(object: unknown): T { ); } -export function getImageTagByArch(tag = CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG): string { +function getImageTagByArch(tag: string): string { // Check CPU architecture const arch = process.arch; if (arch === "arm64" && !tag.endsWith("-arm")) { @@ -244,6 +245,14 @@ export function getImageTagByArch(tag = CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG): str return tag; } +export function getCairoCliImageTagByArch(tag = CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG): string { + return getImageTagByArch(tag); +} + +export function getDevnetImageTagByArch(tag = DEFAULT_DEVNET_DOCKER_IMAGE_TAG): string { + return getImageTagByArch(tag); +} + export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } From 1b2d67e2f353f36e0dd3822a75ab3d9d9a9a41ae Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 10:30:58 +0200 Subject: [PATCH 24/51] Fix hardhat config; add validation --- scripts/test.sh | 2 ++ test/configuration-tests/with-scarb-path/hardhat.config.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/test.sh b/scripts/test.sh index 3b1931af..19c630db 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -51,6 +51,8 @@ function run_test() { return 0 fi + # validate config file + npx hardhat --typecheck --config "$config_file_path" # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" diff --git a/test/configuration-tests/with-scarb-path/hardhat.config.ts b/test/configuration-tests/with-scarb-path/hardhat.config.ts index c42d100e..40bec312 100644 --- a/test/configuration-tests/with-scarb-path/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-path/hardhat.config.ts @@ -3,7 +3,7 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { network: process.env.NETWORK, - scarb: "scarb" + scarbCommand: "scarb" }, networks: { devnet: { From 85988be5279d8884c25fa69e85b9eb0eb5e59fbc Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 10:51:54 +0200 Subject: [PATCH 25/51] Use /tmp for scarb cache dir --- src/scarb-wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index fff1301c..41231e42 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -48,7 +48,7 @@ export class DockerizedScarbWrapper extends ScarbWrapper { // If not specified, inside the container it tries to write cache to /.cache // which is not allowed for a non-root user. So here we are setting it to the path used by Scarb // in many non-docker environments - const globalCacheDir = path.join(os.homedir(), ".cache", "scarb"); + const globalCacheDir = path.join(os.tmpdir(), ".cache", "scarb"); const execution = spawnSync("docker", [ "run", "--rm", From 697757623032b9cd1fb011019a87be3739a30628 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 10:58:13 +0200 Subject: [PATCH 26/51] Add venv test --- test/venv-tests/with-scarb-custom-command/check.ts | 14 ++++++++++++++ .../with-scarb-custom-command/hardhat.config.ts | 14 ++++++++++++++ .../with-scarb-custom-command/network.json | 4 ++++ 3 files changed, 32 insertions(+) create mode 100644 test/venv-tests/with-scarb-custom-command/check.ts create mode 100644 test/venv-tests/with-scarb-custom-command/hardhat.config.ts create mode 100644 test/venv-tests/with-scarb-custom-command/network.json diff --git a/test/venv-tests/with-scarb-custom-command/check.ts b/test/venv-tests/with-scarb-custom-command/check.ts new file mode 100644 index 00000000..a259f4bd --- /dev/null +++ b/test/venv-tests/with-scarb-custom-command/check.ts @@ -0,0 +1,14 @@ +import { hardhatStarknetBuild } from "../../utils/cli-functions"; +import { scarbAssertions } from "../../utils/scarb-utils"; +import { assertContains } from "../../utils/utils"; + +// A duplicate of configuration-tests/with-scarb-path +// Useful because: +// - it tests if the generated artifacts can be used in venv mode +// - it is run in macos tests + +const projectName = "cairo1_sample_project"; +const buildResult = hardhatStarknetBuild([projectName]); +assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); + +scarbAssertions(projectName); diff --git a/test/venv-tests/with-scarb-custom-command/hardhat.config.ts b/test/venv-tests/with-scarb-custom-command/hardhat.config.ts new file mode 100644 index 00000000..670504fd --- /dev/null +++ b/test/venv-tests/with-scarb-custom-command/hardhat.config.ts @@ -0,0 +1,14 @@ +import "@shardlabs/starknet-hardhat-plugin"; + +module.exports = { + starknet: { + venv: "../my-venv", + network: process.env.NETWORK, + scarbCommand: "scarb" + }, + networks: { + devnet: { + url: "http://127.0.0.1:5050" + } + } +}; diff --git a/test/venv-tests/with-scarb-custom-command/network.json b/test/venv-tests/with-scarb-custom-command/network.json new file mode 100644 index 00000000..f1977760 --- /dev/null +++ b/test/venv-tests/with-scarb-custom-command/network.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../network.schema", + "devnet": true +} From 7219c1d010bb66bac117d2c587d0dc304173c355 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 10:58:33 +0200 Subject: [PATCH 27/51] Rename scarb-path test to scarb-custom-command --- .../check.ts | 0 .../hardhat.config.ts | 0 .../network.json | 0 .../{with-scarb-path => with-scarb-custom-command}/check.ts | 0 .../hardhat.config.ts | 0 .../{with-scarb-path => with-scarb-custom-command}/network.json | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename test/configuration-tests/{with-scarb-cli-path => with-scarb-custom-command-cli}/check.ts (100%) rename test/configuration-tests/{with-scarb-cli-path => with-scarb-custom-command-cli}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-cli-path => with-scarb-custom-command-cli}/network.json (100%) rename test/configuration-tests/{with-scarb-path => with-scarb-custom-command}/check.ts (100%) rename test/configuration-tests/{with-scarb-path => with-scarb-custom-command}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-path => with-scarb-custom-command}/network.json (100%) diff --git a/test/configuration-tests/with-scarb-cli-path/check.ts b/test/configuration-tests/with-scarb-custom-command-cli/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-cli-path/check.ts rename to test/configuration-tests/with-scarb-custom-command-cli/check.ts diff --git a/test/configuration-tests/with-scarb-cli-path/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-command-cli/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-cli-path/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-command-cli/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-cli-path/network.json b/test/configuration-tests/with-scarb-custom-command-cli/network.json similarity index 100% rename from test/configuration-tests/with-scarb-cli-path/network.json rename to test/configuration-tests/with-scarb-custom-command-cli/network.json diff --git a/test/configuration-tests/with-scarb-path/check.ts b/test/configuration-tests/with-scarb-custom-command/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-path/check.ts rename to test/configuration-tests/with-scarb-custom-command/check.ts diff --git a/test/configuration-tests/with-scarb-path/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-path/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-command/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-path/network.json b/test/configuration-tests/with-scarb-custom-command/network.json similarity index 100% rename from test/configuration-tests/with-scarb-path/network.json rename to test/configuration-tests/with-scarb-custom-command/network.json From bea4036b0521337ed7d299c78aed8b6c21380456 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 11:05:55 +0200 Subject: [PATCH 28/51] Move hardhat config validation after cp --- scripts/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index 19c630db..c2c8b8bd 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -51,10 +51,10 @@ function run_test() { return 0 fi - # validate config file - npx hardhat --typecheck --config "$config_file_path" # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" + # validate config file + npx hardhat --typecheck --config "$CONFIG_FILE_NAME" # check if test_case/check.ts exists if [ -f "$test_case/check.ts" ]; then From 8380037abaae1b83a8f7972bc6e2d0dcb23b3bab Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 11:40:08 +0200 Subject: [PATCH 29/51] Check scarb installation --- scripts/test-setup.sh | 2 ++ scripts/test.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index fa5c4511..05950971 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -37,3 +37,5 @@ fi # install scarb SCARB_VERSION=$(jq -r ".SCARB_VERSION" ../config.json) curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v "$SCARB_VERSION" +echo "Using Scarb version:" +scarb --version \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh index c2c8b8bd..f8a3030c 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -54,7 +54,7 @@ function run_test() { # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" # validate config file - npx hardhat --typecheck --config "$CONFIG_FILE_NAME" + npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1> /dev/null # check if test_case/check.ts exists if [ -f "$test_case/check.ts" ]; then From 09e9f125d01166d2aa0383c7423f4eeaf4df2439 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 11:49:32 +0200 Subject: [PATCH 30/51] Prevent invalid config from exiting test.sh --- scripts/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.sh b/scripts/test.sh index f8a3030c..49bc5f84 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -54,7 +54,7 @@ function run_test() { # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" # validate config file - npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1> /dev/null + npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1> /dev/null || echo "Invalid config file!" # check if test_case/check.ts exists if [ -f "$test_case/check.ts" ]; then From e9e1edc5ddaf23c5c46e837e4643113ac2f22ce7 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 12:19:27 +0200 Subject: [PATCH 31/51] Fix scarb installation --- scripts/test-setup.sh | 2 -- src/scarb-wrapper.ts | 5 +++-- .../with-scarb-custom-command/hardhat.config.ts | 2 +- test/venv-tests/with-scarb-custom-command/hardhat.config.ts | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index 05950971..fa5c4511 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -37,5 +37,3 @@ fi # install scarb SCARB_VERSION=$(jq -r ".SCARB_VERSION" ../config.json) curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v "$SCARB_VERSION" -echo "Using Scarb version:" -scarb --version \ No newline at end of file diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 41231e42..8668f814 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -81,9 +81,10 @@ export class CustomScarbWrapper extends ScarbWrapper { // validate const execution = spawnSync(scarbCommand, ["--version"]); - if (execution.status) { + // on mac, properties of spawnSync result can be null if invalid command + if (execution.status !== 0) { throw new StarknetPluginError( - `Not a legal executable Scarb command: ${scarbCommand}.\n${execution.stderr.toString()}` + `Not a legal executable Scarb command: ${scarbCommand}.\n${execution?.stderr.toString()}` ); } diff --git a/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts index 40bec312..97d9175b 100644 --- a/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts @@ -3,7 +3,7 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { network: process.env.NETWORK, - scarbCommand: "scarb" + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { diff --git a/test/venv-tests/with-scarb-custom-command/hardhat.config.ts b/test/venv-tests/with-scarb-custom-command/hardhat.config.ts index 670504fd..6e46766f 100644 --- a/test/venv-tests/with-scarb-custom-command/hardhat.config.ts +++ b/test/venv-tests/with-scarb-custom-command/hardhat.config.ts @@ -4,7 +4,7 @@ module.exports = { starknet: { venv: "../my-venv", network: process.env.NETWORK, - scarbCommand: "scarb" + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { From 4bde2eff069c42faaf5187500df6e5cb7c9c5943 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 12:27:17 +0200 Subject: [PATCH 32/51] Prevent solidity recompilation in scarb tests --- test/utils/scarb-utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/scarb-utils.ts b/test/utils/scarb-utils.ts index 984094ba..3f78a86f 100644 --- a/test/utils/scarb-utils.ts +++ b/test/utils/scarb-utils.ts @@ -38,7 +38,7 @@ function assertDeclarable( const oldEnvVarValue = process.env.DECLARABLE_CONTRACT; process.env.DECLARABLE_CONTRACT = compoundContractName; try { - hardhatStarknetRun(["scripts/declare.ts"]); + hardhatStarknetRun(["scripts/declare.ts", "--no-compile"]); } finally { // restore process.env.DECLARABLE_CONTRACT = oldEnvVarValue; @@ -58,5 +58,5 @@ export function scarbAssertions(projectName: string, packageName = DEFAULT_PACKA // attempt full declare+deploy+call on FibContract // if it was declared earlier with the rest, this script would fail - hardhatStarknetTest(["test/cairo1/fib-contract.test.ts"]); + hardhatStarknetTest(["test/cairo1/fib-contract.test.ts", "--no-compile"]); } From 53156750dab4e861d8001c1c62b7a8bea1e404b8 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 12:29:32 +0200 Subject: [PATCH 33/51] Fix fetching devnet image --- src/external-server/create-devnet-wrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/external-server/create-devnet-wrapper.ts b/src/external-server/create-devnet-wrapper.ts index 844b8830..d7bd2cdb 100644 --- a/src/external-server/create-devnet-wrapper.ts +++ b/src/external-server/create-devnet-wrapper.ts @@ -2,7 +2,7 @@ import { HardhatNetworkConfig, HardhatRuntimeEnvironment } from "hardhat/types"; import { StarknetPluginError } from "../starknet-plugin-error"; import { DEVNET_DOCKER_REPOSITORY, INTEGRATED_DEVNET, INTEGRATED_DEVNET_URL } from "../constants"; -import { getCairoCliImageTagByArch, getNetwork } from "../utils"; +import { getCairoCliImageTagByArch, getDevnetImageTagByArch, getNetwork } from "../utils"; import { DockerDevnet } from "./docker-devnet"; import { VenvDevnet } from "./venv-devnet"; import { ExternalServer } from "./external-server"; @@ -37,7 +37,7 @@ export function createIntegratedDevnet(hre: HardhatRuntimeEnvironment): External ); } - const tag = getCairoCliImageTagByArch(devnetNetwork.dockerizedVersion); + const tag = getDevnetImageTagByArch(devnetNetwork.dockerizedVersion); return new DockerDevnet( { repository: DEVNET_DOCKER_REPOSITORY, From f4fb456dad78df6302c9ec5698c59203c7e38ac3 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 12:34:17 +0200 Subject: [PATCH 34/51] Fix lint error --- src/external-server/create-devnet-wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/external-server/create-devnet-wrapper.ts b/src/external-server/create-devnet-wrapper.ts index d7bd2cdb..c5c1c9f0 100644 --- a/src/external-server/create-devnet-wrapper.ts +++ b/src/external-server/create-devnet-wrapper.ts @@ -2,7 +2,7 @@ import { HardhatNetworkConfig, HardhatRuntimeEnvironment } from "hardhat/types"; import { StarknetPluginError } from "../starknet-plugin-error"; import { DEVNET_DOCKER_REPOSITORY, INTEGRATED_DEVNET, INTEGRATED_DEVNET_URL } from "../constants"; -import { getCairoCliImageTagByArch, getDevnetImageTagByArch, getNetwork } from "../utils"; +import { getDevnetImageTagByArch, getNetwork } from "../utils"; import { DockerDevnet } from "./docker-devnet"; import { VenvDevnet } from "./venv-devnet"; import { ExternalServer } from "./external-server"; From 90731728836951828c772d92509b01c9991732da Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 12:48:56 +0200 Subject: [PATCH 35/51] chown /tmp on circleci --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 796059da..c1a814b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -201,7 +201,9 @@ jobs: steps: - run: name: Add file permissions - command: sudo chown -R circleci /usr/local/bin + command: | + sudo chown -R circleci /usr/local/bin + sudo chwon -R circleci /tmp # Retrieve the latest versions of the dependencies - fetch_dependecies_version From edb1e2ef2369c1b4d529b053eb846706c6da875b Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:23:08 +0200 Subject: [PATCH 36/51] Remove venv-tests/with-scarb-custom-command --- test/venv-tests/with-scarb-custom-command/check.ts | 14 -------------- .../with-scarb-custom-command/hardhat.config.ts | 14 -------------- .../with-scarb-custom-command/network.json | 4 ---- 3 files changed, 32 deletions(-) delete mode 100644 test/venv-tests/with-scarb-custom-command/check.ts delete mode 100644 test/venv-tests/with-scarb-custom-command/hardhat.config.ts delete mode 100644 test/venv-tests/with-scarb-custom-command/network.json diff --git a/test/venv-tests/with-scarb-custom-command/check.ts b/test/venv-tests/with-scarb-custom-command/check.ts deleted file mode 100644 index a259f4bd..00000000 --- a/test/venv-tests/with-scarb-custom-command/check.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { hardhatStarknetBuild } from "../../utils/cli-functions"; -import { scarbAssertions } from "../../utils/scarb-utils"; -import { assertContains } from "../../utils/utils"; - -// A duplicate of configuration-tests/with-scarb-path -// Useful because: -// - it tests if the generated artifacts can be used in venv mode -// - it is run in macos tests - -const projectName = "cairo1_sample_project"; -const buildResult = hardhatStarknetBuild([projectName]); -assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); - -scarbAssertions(projectName); diff --git a/test/venv-tests/with-scarb-custom-command/hardhat.config.ts b/test/venv-tests/with-scarb-custom-command/hardhat.config.ts deleted file mode 100644 index 6e46766f..00000000 --- a/test/venv-tests/with-scarb-custom-command/hardhat.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import "@shardlabs/starknet-hardhat-plugin"; - -module.exports = { - starknet: { - venv: "../my-venv", - network: process.env.NETWORK, - scarbCommand: `${process.env.HOME}/.local/bin/scarb` - }, - networks: { - devnet: { - url: "http://127.0.0.1:5050" - } - } -}; diff --git a/test/venv-tests/with-scarb-custom-command/network.json b/test/venv-tests/with-scarb-custom-command/network.json deleted file mode 100644 index f1977760..00000000 --- a/test/venv-tests/with-scarb-custom-command/network.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "../../network.schema", - "devnet": true -} From bcd8363a1130af7e4b8f00d80b52f6e4bfd62d1e Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:25:45 +0200 Subject: [PATCH 37/51] Suspend configuration-tests/disallow-cairo1BinDir-when-dockerized --- .../disallow-cairo1BinDir-when-dockerized/check.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts b/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts index 96a12f5f..9999eca0 100644 --- a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts +++ b/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts @@ -1,5 +1,15 @@ +import { exit } from "process"; import { hardhatStarknetTest } from "../../utils/cli-functions"; import { assertContains } from "../../utils/utils"; +console.log( + "This test is suspended and can be removed in the future when we change how compiler version is selected" +); +console.log( + "Read more here:", + "https://github.com/0xSpaceShard/starknet-hardhat-plugin/issues/384" +); + +exit(0); const execution = hardhatStarknetTest(["--no-compile", "test/quick-test.ts"], true); assertContains(execution.stderr, "cairo1BinDir cannot be used with dockerized plugin"); From 607cf9c40d8ec2496a70b7519d7d6ca78986bbd4 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:31:18 +0200 Subject: [PATCH 38/51] Fix typo --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c1a814b3..3634c1a2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -203,7 +203,7 @@ jobs: name: Add file permissions command: | sudo chown -R circleci /usr/local/bin - sudo chwon -R circleci /tmp + sudo chown -R circleci /tmp # Retrieve the latest versions of the dependencies - fetch_dependecies_version From 600ff712ca90004e63ae45ff5e085e2134945a92 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:45:25 +0200 Subject: [PATCH 39/51] Fix scarb init error logging --- src/scarb-wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 8668f814..24f2abf2 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -84,7 +84,7 @@ export class CustomScarbWrapper extends ScarbWrapper { // on mac, properties of spawnSync result can be null if invalid command if (execution.status !== 0) { throw new StarknetPluginError( - `Not a legal executable Scarb command: ${scarbCommand}.\n${execution?.stderr.toString()}` + `Not a legal executable Scarb command: ${scarbCommand}.\n${execution.stderr?.toString()}` ); } From 392059ced8cc9d15e68783d2c4e3bcbe341e556a Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:46:03 +0200 Subject: [PATCH 40/51] Remove test/configuration-tests/disallow-cairo1BinDir-when-dockerized --- .../check.ts | 15 --------------- .../hardhat.config.ts | 15 --------------- .../network.json | 4 ---- 3 files changed, 34 deletions(-) delete mode 100644 test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts delete mode 100644 test/configuration-tests/disallow-cairo1BinDir-when-dockerized/hardhat.config.ts delete mode 100644 test/configuration-tests/disallow-cairo1BinDir-when-dockerized/network.json diff --git a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts b/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts deleted file mode 100644 index 9999eca0..00000000 --- a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/check.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { exit } from "process"; -import { hardhatStarknetTest } from "../../utils/cli-functions"; -import { assertContains } from "../../utils/utils"; - -console.log( - "This test is suspended and can be removed in the future when we change how compiler version is selected" -); -console.log( - "Read more here:", - "https://github.com/0xSpaceShard/starknet-hardhat-plugin/issues/384" -); - -exit(0); -const execution = hardhatStarknetTest(["--no-compile", "test/quick-test.ts"], true); -assertContains(execution.stderr, "cairo1BinDir cannot be used with dockerized plugin"); diff --git a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/hardhat.config.ts b/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/hardhat.config.ts deleted file mode 100644 index 737a9a19..00000000 --- a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/hardhat.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import "@shardlabs/starknet-hardhat-plugin"; - -module.exports = { - starknet: { - // defaulting to dockerizedVenv - - // supply any path to make it fail in combination with dockerized - cairo1BinDir: "dummy/path" - }, - networks: { - devnet: { - url: "http://127.0.0.1:5050" - } - } -}; diff --git a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/network.json b/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/network.json deleted file mode 100644 index f1977760..00000000 --- a/test/configuration-tests/disallow-cairo1BinDir-when-dockerized/network.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "../../network.schema", - "devnet": true -} From 095ed7b831bd846397a287a04d5404b54ed3d6dd Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 13:46:29 +0200 Subject: [PATCH 41/51] Fix with-scarb-custom-command-cli test --- .../configuration-tests/with-scarb-custom-command-cli/check.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/configuration-tests/with-scarb-custom-command-cli/check.ts b/test/configuration-tests/with-scarb-custom-command-cli/check.ts index b3b52c8d..86524909 100644 --- a/test/configuration-tests/with-scarb-custom-command-cli/check.ts +++ b/test/configuration-tests/with-scarb-custom-command-cli/check.ts @@ -4,7 +4,8 @@ import { assertContains } from "../../utils/utils"; const projectName = "cairo1_sample_project"; // override the default of using dockerized Scarb -const buildResult = hardhatStarknetBuild([projectName, "--scarb-command", "scarb"]); +const customCommand = `${process.env.HOME}/.local/bin/scarb`; +const buildResult = hardhatStarknetBuild([projectName, "--scarb-command", customCommand]); assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); scarbAssertions(projectName); From c9bc3e31b7cd7e11afac2c0b27a9b731bda096fe Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 14:55:05 +0200 Subject: [PATCH 42/51] Disable dockerized scarb --- src/scarb-wrapper.ts | 19 ++++++++++++------- .../check.ts | 0 .../hardhat.config.ts | 0 .../network.json | 0 .../check.ts | 0 .../hardhat.config.ts | 0 .../multiple_contracts_invalid.cairo | 0 .../network.json | 0 .../Scarb-invalid.toml | 0 .../check.ts | 0 .../hardhat.config.ts | 0 .../network.json | 0 .../check.ts | 2 +- .../hardhat.config.ts | 0 .../network.json | 0 .../check.ts | 0 .../hardhat.config.ts | 0 .../network.json | 0 .../with-scarb-dockerized/check.ts | 7 ++----- 19 files changed, 15 insertions(+), 13 deletions(-) rename test/configuration-tests/{with-scarb-custom-command-cli => with-scarb-custom-cli}/check.ts (100%) rename test/configuration-tests/{with-scarb-custom-command-cli => with-scarb-custom-cli}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-custom-command-cli => with-scarb-custom-cli}/network.json (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-cairo => with-scarb-custom-invalid-cairo}/check.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-cairo => with-scarb-custom-invalid-cairo}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-cairo => with-scarb-custom-invalid-cairo}/multiple_contracts_invalid.cairo (100%) rename test/configuration-tests/{with-scarb-custom-command => with-scarb-custom-invalid-cairo}/network.json (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-config => with-scarb-custom-invalid-config}/Scarb-invalid.toml (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-config => with-scarb-custom-invalid-config}/check.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-config => with-scarb-custom-invalid-config}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-cairo => with-scarb-custom-invalid-config}/network.json (100%) rename test/configuration-tests/{with-scarb-dockerized-multiple-projects => with-scarb-custom-multiple-projects}/check.ts (88%) rename test/configuration-tests/{with-scarb-dockerized-multiple-projects => with-scarb-custom-multiple-projects}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-invalid-config => with-scarb-custom-multiple-projects}/network.json (100%) rename test/configuration-tests/{with-scarb-custom-command => with-scarb-custom}/check.ts (100%) rename test/configuration-tests/{with-scarb-custom-command => with-scarb-custom}/hardhat.config.ts (100%) rename test/configuration-tests/{with-scarb-dockerized-multiple-projects => with-scarb-custom}/network.json (100%) diff --git a/src/scarb-wrapper.ts b/src/scarb-wrapper.ts index 24f2abf2..9cc82b25 100644 --- a/src/scarb-wrapper.ts +++ b/src/scarb-wrapper.ts @@ -2,8 +2,7 @@ import { ProcessResult } from "@nomiclabs/hardhat-docker"; import { spawnSync } from "child_process"; import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types"; import { StarknetPluginError } from "./starknet-plugin-error"; -import { CAIRO_CLI_DOCKER_REPOSITORY, PLUGIN_NAME } from "./constants"; -import { getCairoCliImageTagByArch } from "./utils"; +import { PLUGIN_NAME } from "./constants"; import path from "path"; import os from "os"; @@ -35,11 +34,17 @@ export class DockerizedScarbWrapper extends ScarbWrapper { constructor(imageTag: string, private projectRootPath: string) { super(); - const repository = CAIRO_CLI_DOCKER_REPOSITORY; - const tag = getCairoCliImageTagByArch(imageTag); - this.formattedImage = `${repository}:${tag}`; - - console.log(`${PLUGIN_NAME} plugin using dockerized Scarb (${this.formattedImage})`); + throw new StarknetPluginError( + "Dockerized Scarb is not yet supported. " + + "If you have Scarb installed on your machine, provide its path via scarbCommand in hardhat config, " + + "or via --scarb-command of hardhat starknet-build" + ); + // UNCOMMENT THIS WHEN DOCKERIZED SCARB SUPPORTED + // const repository = CAIRO_CLI_DOCKER_REPOSITORY; + // const tag = getCairoCliImageTagByArch(imageTag); + // this.formattedImage = `${repository}:${tag}`; + + // console.log(`${PLUGIN_NAME} plugin using dockerized Scarb (${this.formattedImage})`); } public override build(packageConfigPath: string, artifactDirPath: string): ProcessResult { diff --git a/test/configuration-tests/with-scarb-custom-command-cli/check.ts b/test/configuration-tests/with-scarb-custom-cli/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-custom-command-cli/check.ts rename to test/configuration-tests/with-scarb-custom-cli/check.ts diff --git a/test/configuration-tests/with-scarb-custom-command-cli/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-custom-command-cli/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-custom-command-cli/network.json b/test/configuration-tests/with-scarb-custom-cli/network.json similarity index 100% rename from test/configuration-tests/with-scarb-custom-command-cli/network.json rename to test/configuration-tests/with-scarb-custom-cli/network.json diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts b/test/configuration-tests/with-scarb-custom-invalid-cairo/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-cairo/check.ts rename to test/configuration-tests/with-scarb-custom-invalid-cairo/check.ts diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-cairo/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo b/test/configuration-tests/with-scarb-custom-invalid-cairo/multiple_contracts_invalid.cairo similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-cairo/multiple_contracts_invalid.cairo rename to test/configuration-tests/with-scarb-custom-invalid-cairo/multiple_contracts_invalid.cairo diff --git a/test/configuration-tests/with-scarb-custom-command/network.json b/test/configuration-tests/with-scarb-custom-invalid-cairo/network.json similarity index 100% rename from test/configuration-tests/with-scarb-custom-command/network.json rename to test/configuration-tests/with-scarb-custom-invalid-cairo/network.json diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml b/test/configuration-tests/with-scarb-custom-invalid-config/Scarb-invalid.toml similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-config/Scarb-invalid.toml rename to test/configuration-tests/with-scarb-custom-invalid-config/Scarb-invalid.toml diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts b/test/configuration-tests/with-scarb-custom-invalid-config/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-config/check.ts rename to test/configuration-tests/with-scarb-custom-invalid-config/check.ts diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-config/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json b/test/configuration-tests/with-scarb-custom-invalid-config/network.json similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-cairo/network.json rename to test/configuration-tests/with-scarb-custom-invalid-config/network.json diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts b/test/configuration-tests/with-scarb-custom-multiple-projects/check.ts similarity index 88% rename from test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts rename to test/configuration-tests/with-scarb-custom-multiple-projects/check.ts index af94b8f6..a5a09fce 100644 --- a/test/configuration-tests/with-scarb-dockerized-multiple-projects/check.ts +++ b/test/configuration-tests/with-scarb-custom-multiple-projects/check.ts @@ -10,7 +10,7 @@ const copiedProjectName = "cairo1_copied_project"; fs.cpSync(projectName, copiedProjectName, { recursive: true }); const buildResult = hardhatStarknetBuild([projectName, copiedProjectName]); -assertContains(buildResult.stdout, "Starknet plugin using dockerized Scarb"); +assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); scarbArtifactsAssertion(projectName); scarbArtifactsAssertion(copiedProjectName); diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-multiple-projects/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-dockerized-invalid-config/network.json b/test/configuration-tests/with-scarb-custom-multiple-projects/network.json similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-invalid-config/network.json rename to test/configuration-tests/with-scarb-custom-multiple-projects/network.json diff --git a/test/configuration-tests/with-scarb-custom-command/check.ts b/test/configuration-tests/with-scarb-custom/check.ts similarity index 100% rename from test/configuration-tests/with-scarb-custom-command/check.ts rename to test/configuration-tests/with-scarb-custom/check.ts diff --git a/test/configuration-tests/with-scarb-custom-command/hardhat.config.ts b/test/configuration-tests/with-scarb-custom/hardhat.config.ts similarity index 100% rename from test/configuration-tests/with-scarb-custom-command/hardhat.config.ts rename to test/configuration-tests/with-scarb-custom/hardhat.config.ts diff --git a/test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json b/test/configuration-tests/with-scarb-custom/network.json similarity index 100% rename from test/configuration-tests/with-scarb-dockerized-multiple-projects/network.json rename to test/configuration-tests/with-scarb-custom/network.json diff --git a/test/configuration-tests/with-scarb-dockerized/check.ts b/test/configuration-tests/with-scarb-dockerized/check.ts index 94ad5ca9..39d59899 100644 --- a/test/configuration-tests/with-scarb-dockerized/check.ts +++ b/test/configuration-tests/with-scarb-dockerized/check.ts @@ -1,9 +1,6 @@ import { hardhatStarknetBuild } from "../../utils/cli-functions"; -import { scarbAssertions } from "../../utils/scarb-utils"; import { assertContains } from "../../utils/utils"; const projectName = "cairo1_sample_project"; -const buildResult = hardhatStarknetBuild([projectName]); -assertContains(buildResult.stdout, "Starknet plugin using dockerized Scarb"); - -scarbAssertions(projectName); +const buildResult = hardhatStarknetBuild([projectName], true); +assertContains(buildResult.stdout, "Dockerized Scarb is not yet supported"); From fa08116ec45cfb4b9c3169b7749bdf128bac2863 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 15:04:16 +0200 Subject: [PATCH 43/51] Fix dockerized scarb test --- test/configuration-tests/with-scarb-dockerized/check.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/configuration-tests/with-scarb-dockerized/check.ts b/test/configuration-tests/with-scarb-dockerized/check.ts index 39d59899..c8d6831f 100644 --- a/test/configuration-tests/with-scarb-dockerized/check.ts +++ b/test/configuration-tests/with-scarb-dockerized/check.ts @@ -3,4 +3,5 @@ import { assertContains } from "../../utils/utils"; const projectName = "cairo1_sample_project"; const buildResult = hardhatStarknetBuild([projectName], true); -assertContains(buildResult.stdout, "Dockerized Scarb is not yet supported"); +console.log("Temporarily expecting that dockerized scarb cannot be used"); +assertContains(buildResult.stderr, "Dockerized Scarb is not yet supported"); From 583393688f0a14eb4c8a4aacad2c06098002398d Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 15:30:12 +0200 Subject: [PATCH 44/51] Add docs [skip ci] --- src/index.ts | 13 +++++++++++-- www/docs/intro.md | 48 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index addd582d..d47f7121 100644 --- a/src/index.ts +++ b/src/index.ts @@ -250,7 +250,8 @@ task("starknet-compile", "Compiles Starknet (Cairo 1) contracts") "paths", "The paths are source files of contracts to be compiled.\n" + "Each of the provided paths is recursively looked into while searching for source files.\n" + - "If no paths are provided, the default contracts directory is traversed." + "If no paths are provided, the default contracts directory is traversed.\n" + + "To build more complex Cairo 1 projects, read about `hardhat starknet-build`" ) .addOptionalParam( "cairo1BinDir", @@ -271,7 +272,15 @@ task("starknet-build", "Builds Scarb projects") "paths", "The paths are source files of contracts to be compiled.\n" + "Each of the provided paths is recursively looked into while searching for Scarb projects.\n" + - "If no paths are provided, the default contracts directory is traversed." + "If no paths are provided, the default contracts directory is traversed.\n" + + "Each project must specify a Scarb.toml file with `sierra` and `casm` set to `true` under [[target.starknet-contract]].\n" + + "In code, load the generated contracts with an underscore-separated string:\n" + + "\tstarknet.getContractFactory('_')\n" + + "E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with:\n" + + "\tstarknet.getContractFactory('MyPackage_FooContract')\n" + + "The name of the file where the contract was defined doesn't play a role.\n" + + "If you do not provide a `scarbCommand` (either an exact command or the path to it) under `starknet` in your hardhat config file, " + + "you may specify (and even override) it via `--scarb-command `." ) .addOptionalParam( "scarbCommand", diff --git a/www/docs/intro.md b/www/docs/intro.md index c4533e98..a33a8a31 100644 --- a/www/docs/intro.md +++ b/www/docs/intro.md @@ -80,6 +80,36 @@ Compiles Starknet Cairo 1 contracts in the provided path. Paths can be files and By default, the dockerized Cairo 1 compiler is used. In [venv mode](#existing-virtual-environment), you can use a custom compiler by providing the path of the directory of its binary executable to `--cairo1-bin-dir` or to the `cairo1BinDir` option in your hardhat config file. Other CLI options are the same as in the [native Cairo compiler](https://github.com/starkware-libs/cairo). +To build more complex Cairo 1 projects, read about `hardhat starknet-build`. + +### `starknet-build` + +``` +$ npx hardhat starknet-build [PATH...] [--scarb-command ] [--skip-validate] +``` + +Builds Scarb projects. + +Each of the provided paths is recursively looked into while searching for Scarb projects. If no paths are provided, the default contracts directory is traversed. + +Each project must specify a Scarb.toml file with `sierra` and `casm` set to `true` under `[[target.starknet-contract]]`. If you know what you are doing, you can skip the validation by providing `--skip-validate`. + +In code, load the generated contracts with an underscore-separated string: + +```js +starknet.getContractFactory("_"); +``` + +E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with: + +```js +starknet.getContractFactory("MyPackage_FooContract"); +``` + +The name of the file where the contract was defined doesn't play a role. + +If you do not provide a `scarbCommand` (either an exact command or the path to it) under `starknet` in your hardhat config file, you may specify (and even override) it via `--scarb-command `. + ### `starknet-verify` ``` @@ -531,9 +561,11 @@ module.exports = { }; ``` -### Custom Cairo 1 compilation +### Single Cairo 1 file compilation + +If you're looking for a way to compile simple Cairo 1 contracts, read on. If you want to build more complex projects, read about [Building Cairo 1 projects](#building-cairo-1-projects) -If you're using `dockerizedVersion`, it will also use the dockerized Cairo 1 compiler version (currently alpha.6). To specify your custom Cairo 1 compiler, you need to provide the path to the directory with its binary executables (likely a subdirectory of the target directory of your compiler repo). This can be configured in `hardhat.config.ts` or in [the CLI](#starknet-compile). +If you're using `dockerizedVersion`, it will also use the dockerized Cairo 1 compiler version (currently 1.1.0). To specify your custom Cairo 1 compiler, you need to provide the path to the directory with its binary executables (likely a subdirectory of the target directory of your compiler repo). This can be configured in `hardhat.config.ts` or in [the CLI](#starknet-compile). ```typescript module.exports = { @@ -544,6 +576,18 @@ module.exports = { }; ``` +### Building Cairo 1 projects + +This plugin comes with a Scarb wrapper. Read about how to use it in [this section](#starknet-build). If not via CLI, you may specify the Scarb command via: + +```typescript +module.exports = { + starknet: { + scarbCommand: "scarb" // or alternatively an exact path to the desired command + } +}; +``` + ### Request Timeout Default requestTimeout is 30s. It can be changed using the following configuration. From a7a42cbb5186d87b74456d1b7f50f30174e51648 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 15:35:27 +0200 Subject: [PATCH 45/51] Fix scarb tests --- .../with-scarb-custom-cli/hardhat.config.ts | 3 ++- .../with-scarb-custom-invalid-cairo/hardhat.config.ts | 3 ++- .../with-scarb-custom-multiple-projects/hardhat.config.ts | 3 ++- www/docs/intro.md | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts index f568acd8..97d9175b 100644 --- a/test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-custom-cli/hardhat.config.ts @@ -2,7 +2,8 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { - network: process.env.NETWORK + network: process.env.NETWORK, + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { diff --git a/test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts index f568acd8..97d9175b 100644 --- a/test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-custom-invalid-cairo/hardhat.config.ts @@ -2,7 +2,8 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { - network: process.env.NETWORK + network: process.env.NETWORK, + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { diff --git a/test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts index f568acd8..97d9175b 100644 --- a/test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-custom-multiple-projects/hardhat.config.ts @@ -2,7 +2,8 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { - network: process.env.NETWORK + network: process.env.NETWORK, + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { diff --git a/www/docs/intro.md b/www/docs/intro.md index a33a8a31..57f283b0 100644 --- a/www/docs/intro.md +++ b/www/docs/intro.md @@ -96,13 +96,13 @@ Each project must specify a Scarb.toml file with `sierra` and `casm` set to `tru In code, load the generated contracts with an underscore-separated string: -```js +```typescript starknet.getContractFactory("_"); ``` E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with: -```js +```typescript starknet.getContractFactory("MyPackage_FooContract"); ``` From 68255c5547c247ea28678246e5a01276b26916a6 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 16:07:08 +0200 Subject: [PATCH 46/51] Install starknet-devnet v0.5.4 --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 30544371..202e03e4 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "CAIRO_LANG": "0.11.2", - "STARKNET_DEVNET": "0.5.3", + "STARKNET_DEVNET": "0.5.4", "CAIRO_COMPILER": "v1.1.0", "SCARB_VERSION": "0.4.0" } From 5d1a03681302544757e27000f6ad02838f586bb2 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 16:14:56 +0200 Subject: [PATCH 47/51] Minor fixes after review --- .circleci/config.yml | 4 +--- scripts/test.sh | 4 +++- src/adapt.ts | 2 +- src/index.ts | 2 +- test/configuration-tests/with-scarb-custom-cli/check.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3634c1a2..796059da 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -201,9 +201,7 @@ jobs: steps: - run: name: Add file permissions - command: | - sudo chown -R circleci /usr/local/bin - sudo chown -R circleci /tmp + command: sudo chown -R circleci /usr/local/bin # Retrieve the latest versions of the dependencies - fetch_dependecies_version diff --git a/scripts/test.sh b/scripts/test.sh index 49bc5f84..c92db7db 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -54,7 +54,9 @@ function run_test() { # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" # validate config file - npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1> /dev/null || echo "Invalid config file!" + npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1>/dev/null || + echo "Invalid config file!" && + return 0 # check if test_case/check.ts exists if [ -f "$test_case/check.ts" ]; then diff --git a/src/adapt.ts b/src/adapt.ts index f2923a31..72e670da 100644 --- a/src/adapt.ts +++ b/src/adapt.ts @@ -591,7 +591,7 @@ function generateComplexOutput(raw: bigint[], rawIndex: number, type: string, ab } else { // struct if (!(type in abi)) { - throw new StarknetPluginError(`Type ${type} not present in ABI.` + JSON.stringify(abi)); + throw new StarknetPluginError(`Type ${type} not present in ABI.`); } generatedComplex = {}; diff --git a/src/index.ts b/src/index.ts index d47f7121..9555c82e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -273,7 +273,7 @@ task("starknet-build", "Builds Scarb projects") "The paths are source files of contracts to be compiled.\n" + "Each of the provided paths is recursively looked into while searching for Scarb projects.\n" + "If no paths are provided, the default contracts directory is traversed.\n" + - "Each project must specify a Scarb.toml file with `sierra` and `casm` set to `true` under [[target.starknet-contract]].\n" + + "Each project must specify a Scarb.toml file in its root with `sierra` and `casm` set to `true` under [[target.starknet-contract]].\n" + "In code, load the generated contracts with an underscore-separated string:\n" + "\tstarknet.getContractFactory('_')\n" + "E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with:\n" + diff --git a/test/configuration-tests/with-scarb-custom-cli/check.ts b/test/configuration-tests/with-scarb-custom-cli/check.ts index 86524909..9aa432e6 100644 --- a/test/configuration-tests/with-scarb-custom-cli/check.ts +++ b/test/configuration-tests/with-scarb-custom-cli/check.ts @@ -3,7 +3,7 @@ import { scarbAssertions } from "../../utils/scarb-utils"; import { assertContains } from "../../utils/utils"; const projectName = "cairo1_sample_project"; -// override the default of using dockerized Scarb +// override the default const customCommand = `${process.env.HOME}/.local/bin/scarb`; const buildResult = hardhatStarknetBuild([projectName, "--scarb-command", customCommand]); assertContains(buildResult.stdout, "Starknet plugin using custom Scarb"); From cb154cc4bc5a4cd1b35857a373eb04652c0ca049 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 16:40:20 +0200 Subject: [PATCH 48/51] Improve docs --- src/constants.ts | 1 + src/index.ts | 8 +++++--- www/docs/intro.md | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 3293c76e..d8abe52a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -9,6 +9,7 @@ export const CAIRO1_SIERRA_SUFFIX = ".json"; export const CAIRO1_COMPILE_BIN = "starknet-compile"; export const CAIRO1_SIERRA_COMPILE_BIN = "starknet-sierra-compile"; export const DOCKER_HOST_BIN_PATH = "/usr/local/bin/target/release"; +export const SUPPORTED_SCARB_VERSION = config["SCARB_VERSION"]; export const DEFAULT_STARKNET_SOURCES_PATH = "contracts"; export const DEFAULT_STARKNET_ARTIFACTS_PATH = "starknet-artifacts"; diff --git a/src/index.ts b/src/index.ts index 9555c82e..81969943 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,7 +29,8 @@ import { VOYAGER_MAINNET_VERIFIED_URL, VOYAGER_GOERLI_2_CONTRACT_API_URL, VOYAGER_GOERLI_2_VERIFIED_URL, - StarknetChainId + StarknetChainId, + SUPPORTED_SCARB_VERSION } from "./constants"; import { adaptPath, @@ -273,10 +274,11 @@ task("starknet-build", "Builds Scarb projects") "The paths are source files of contracts to be compiled.\n" + "Each of the provided paths is recursively looked into while searching for Scarb projects.\n" + "If no paths are provided, the default contracts directory is traversed.\n" + - "Each project must specify a Scarb.toml file in its root with `sierra` and `casm` set to `true` under [[target.starknet-contract]].\n" + + `Each project must be a valid Scarb ${SUPPORTED_SCARB_VERSION} project with lib.cairo and Scarb.toml in its root.\n` + + "The toml file must have `sierra` and `casm` set to `true` under [[target.starknet-contract]].\n" + "In code, load the generated contracts with an underscore-separated string:\n" + "\tstarknet.getContractFactory('_')\n" + - "E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with:\n" + + "E.g. if your toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with:\n" + "\tstarknet.getContractFactory('MyPackage_FooContract')\n" + "The name of the file where the contract was defined doesn't play a role.\n" + "If you do not provide a `scarbCommand` (either an exact command or the path to it) under `starknet` in your hardhat config file, " + diff --git a/www/docs/intro.md b/www/docs/intro.md index 57f283b0..22b57c31 100644 --- a/www/docs/intro.md +++ b/www/docs/intro.md @@ -92,7 +92,7 @@ Builds Scarb projects. Each of the provided paths is recursively looked into while searching for Scarb projects. If no paths are provided, the default contracts directory is traversed. -Each project must specify a Scarb.toml file with `sierra` and `casm` set to `true` under `[[target.starknet-contract]]`. If you know what you are doing, you can skip the validation by providing `--skip-validate`. +Each project must be a valid Scarb 0.4.0 project with lib.cairo and Scarb.toml in its root. The toml file must have `sierra` and `casm` set to `true` under `[[target.starknet-contract]]`. If you know what you are doing, you can skip the validation by providing `--skip-validate`. In code, load the generated contracts with an underscore-separated string: @@ -100,7 +100,7 @@ In code, load the generated contracts with an underscore-separated string: starknet.getContractFactory("_"); ``` -E.g. if your Scarb.toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with: +E.g. if your toml specifies `name = MyPackage` and there is a contract called FooContract in your source files, you would load it with: ```typescript starknet.getContractFactory("MyPackage_FooContract"); From eceff40f07aff594ebd9150efce340ef3e42233a Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 16:43:25 +0200 Subject: [PATCH 49/51] Remove hardhat config check --- scripts/test.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index c92db7db..4fa71e24 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -53,10 +53,7 @@ function run_test() { # replace the dummy config (CONFIG_FILE_NAME) with the one used by this test /bin/cp "$config_file_path" "$CONFIG_FILE_NAME" - # validate config file - npx hardhat --typecheck --config "$CONFIG_FILE_NAME" 1>/dev/null || - echo "Invalid config file!" && - return 0 + # in the future - validate config file here # check if test_case/check.ts exists if [ -f "$test_case/check.ts" ]; then From 6b23e53a13405c9971dc62378674f7435ed65d44 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 17:01:46 +0200 Subject: [PATCH 50/51] Fix scarb invalid config test --- .../with-scarb-custom-invalid-config/hardhat.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts b/test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts index f568acd8..97d9175b 100644 --- a/test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts +++ b/test/configuration-tests/with-scarb-custom-invalid-config/hardhat.config.ts @@ -2,7 +2,8 @@ import "@shardlabs/starknet-hardhat-plugin"; module.exports = { starknet: { - network: process.env.NETWORK + network: process.env.NETWORK, + scarbCommand: `${process.env.HOME}/.local/bin/scarb` }, networks: { devnet: { From 1732514b109464e37b1cd19012e8025339ec22d5 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Thu, 22 Jun 2023 17:30:07 +0200 Subject: [PATCH 51/51] Restore example repo branch [skip ci] --- scripts/test-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index fa5c4511..7e3dd3ee 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -12,7 +12,7 @@ trap 'for killable in $(jobs -p); do kill -9 $killable; done' EXIT # setup example repo rm -rf starknet-hardhat-example -EXAMPLE_REPO_BRANCH="adapt-0.11.2" +EXAMPLE_REPO_BRANCH="plugin" if [[ "$CIRCLE_BRANCH" == "master" ]] && [[ "$EXAMPLE_REPO_BRANCH" != "plugin" ]]; then echo "Invalid example repo branch: $EXAMPLE_REPO_BRANCH" exit 1