Skip to content

Commit

Permalink
Adapt to cairo-lang/Starknet 0.11.2; support scarb (#376)
Browse files Browse the repository at this point in the history
* [skip ci] - ci just passed, though without the changes from #393; a new run follows
  • Loading branch information
FabijanC authored Jun 22, 2023
1 parent 13940c1 commit 972213c
Show file tree
Hide file tree
Showing 44 changed files with 749 additions and 79 deletions.
2 changes: 0 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"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.4",
"CAIRO_COMPILER": "v1.1.0",
"SCARB_VERSION": "0.4.0"
}
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 10 additions & 0 deletions scripts/test-setup.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#!/bin/bash

set -eu
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
Expand All @@ -27,3 +33,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"
1 change: 1 addition & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +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"
# in the future - validate config file here

# check if test_case/check.ts exists
if [ -f "$test_case/check.ts" ]; then
Expand Down
4 changes: 2 additions & 2 deletions scripts/versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
58 changes: 34 additions & 24 deletions src/adapt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,33 @@ 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.
Expand Down Expand Up @@ -487,30 +514,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;
Expand Down Expand Up @@ -578,6 +584,10 @@ 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)) {
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
13 changes: 3 additions & 10 deletions src/external-server/create-devnet-wrapper.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
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 { getImageTagByArch, getNetwork } from "../utils";
import { DEVNET_DOCKER_REPOSITORY, INTEGRATED_DEVNET, INTEGRATED_DEVNET_URL } from "../constants";
import { getDevnetImageTagByArch, getNetwork } from "../utils";
import { DockerDevnet } from "./docker-devnet";
import { VenvDevnet } from "./venv-devnet";
import { ExternalServer } from "./external-server";
Expand Down Expand Up @@ -42,9 +37,7 @@ export function createIntegratedDevnet(hre: HardhatRuntimeEnvironment): External
);
}

const tag = getImageTagByArch(
devnetNetwork.dockerizedVersion || DEFAULT_DEVNET_DOCKER_IMAGE_TAG
);
const tag = getDevnetImageTagByArch(devnetNetwork.dockerizedVersion);
return new DockerDevnet(
{
repository: DEVNET_DOCKER_REPOSITORY,
Expand Down
47 changes: 37 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -30,14 +29,15 @@ 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,
getAccountPath,
getCairoCliImageTagByArch,
getDefaultHardhatNetworkConfig,
getDefaultHttpNetworkConfig,
getImageTagByArch,
getNetwork
} from "./utils";
import { DockerWrapper, VenvWrapper } from "./starknet-wrappers";
Expand All @@ -51,7 +51,8 @@ import {
starknetMigrateAction,
starknetNewAccountAction,
starknetDeployAccountAction,
starknetCompileCairo1Action
starknetCompileCairo1Action,
starknetBuildAction
} from "./task-actions";
import {
bigIntToShortStringUtil,
Expand Down Expand Up @@ -195,9 +196,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 = getCairoCliImageTagByArch(hre.config.starknet.dockerizedVersion);

const image = { repository, tag };
const accountPaths = extractAccountPaths(hre);
Expand Down Expand Up @@ -235,7 +234,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(
Expand All @@ -251,8 +250,9 @@ 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" +
"If no paths are provided, the default contracts directory is traversed."
"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.\n" +
"To build more complex Cairo 1 projects, read about `hardhat starknet-build`"
)
.addOptionalParam(
"cairo1BinDir",
Expand All @@ -268,6 +268,33 @@ task("starknet-compile", "Compiles Starknet (Cairo 1) contracts")
.addFlag("addPythonicHints", "Add pythonic hints.")
.setAction(starknetCompileCairo1Action);

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.\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('<PACKAGE_NAME>_<CONTRACT_NAME>')\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, " +
"you may specify (and even override) it via `--scarb-command <COMMAND>`."
)
.addOptionalParam(
"scarbCommand",
"Your local Scarb command or path to the executable file. 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) => {
hre.starknet = {
getContractFactory: async (contractPath) => {
Expand Down
Loading

0 comments on commit 972213c

Please sign in to comment.